Receipts are rows, not columns on the message
is_delivered and is_read on messages would be free to store and wrong for every group. Status is per recipient, so it belongs on a table keyed by message and user. The cost is the fastest-growing table in the product — messages times participants — which is why receipts are usually aged out long before messages are.