Again, this still wouldn't be perfect, but just to add to your $line part that might at least give you something to work with for the time being...

Although $line(window,1) will be lost if your buffer is full and you add a new line and $line(window,0) won't change with a full buffer, this can actually work for you...

Step 1- Set a variable to the buffer size so you can use it later.

Step 2a- While $line(window,0) is less than the buffer variable, see if that total number of lines has changed. If so, you know a line was added.

Step 2b- If $line(window,0) equals or is greater than the buffer variable (greater than is just to catch any possibility of error), then check both $line(window,1) and $line(window,$line(window,0)) at whatever interval you want. If either one changes, then you have a new line.

Catch- Although this works in most cases (even if there are repeated lines at the bottom of the buffer as you mentioned), there is the possibility of having lines 1 and 2 be the same AND the new line matching the previous new line. That would mean that neither first nor last line changed even with an added line. However, this really should be rare unless your window buffer fills with the same error top to bottom as could happen with a bad loop. So I'd say this has somewhere around a 99% success rate, which isn't all that bad unless you absolutely need 100%. If nothing else, it gives you something decent to work with until something better can be set up.

How to increase accuracy further- Track more than just the first and last lines. Pick one or more other lines in the middle and track them as well. This still doesn't help in the case of a bad loop that fills the entire buffer with the same message, but does decrease the chance of randomly having the top lines be the same and have the new line match the previous new line.

Anyhow, just some thoughts that might be at least useful in the meantime.