Gaps & integrity
Blocks are delivered in order, and blocks are hash-linked to their parents. To check continuity, compare each new block's parent hash with the hash of the block before it; they match unless an undo arrived in between. A mismatch means the client missed a message, not that the chain skipped one; reconnect from the last cursor you saved.
On a Firehose response, metadata carries the block's num, id, parent_num, parent_id and time for every chain, so you can check continuity without decoding the block. metadata.lib_num is the last irreversible block when the response was sent.
The continuity check holds for full streams and for filtered streams with send_all_block_headers: true. With send_all_block_headers: false, historical blocks with no matching transaction are skipped, so block numbers jump and a block's parent may not be the previous block you received. To check continuity on a filtered stream, set send_all_block_headers: true.