Unless I'm missing something, there is no bug here.
Here's how each example works:
for $fh.lines -> $line { ... }
The .lines method is only called once, and returns a lazy sequence of lines
(represented as a Seq object). The `for` loop then iterates this sequence.
for $fh.read(1024) -> $byte { ... }
The .read method is only called once, and returns a binary buffer (represented
as a Buf object). The `for` loop then iterates this buffer. It so happens that
iterating a Buf iterates over its bytes, each represented as a number.
while $fh.read(1024) -> $block { ... }
The .read method is called repeatedly, once for each iteration of the while
loop. Each iteration gets a Buf object. The while loop stops when `read`
returns an empty Buf (which evaluates to False in boolean context).