Look down the file a bit, you'll see after successfully reading data they call ParseReceivedData().
Inside the parsing code you can see every packet starts with an int for the size of the packet, followed by a series of details beginning with a request ID int, command ID int, and then details of the command.
Without looking deeper in the code about how they do the buffer, that suggests that if they don't have enough data to actually be a packet they don't bother processing it. Processing it requires memory allocations and releases and hardware access, which are time consuming.
It is possibly an issue if their buffering system or their commands happen to move less than 4 items and then stall for a time, but in most games there is a constant flow of data so that isn't a problem. Data will continue to flow continuously, so it would likely reach the four-byte threshold before the next update is run. If the buffering were configured that way then it might be better to process any amount of data that has been received in case they were mid-data before, but that's a bigger question about the game's performance cost for waiting for data and the time between updates.
As for the minimum buffer size of 1024 bytes, that is probably because time passes and because network hardware runs separate from the program. They query how much data is ready at one moment, but that is at least six lines and potentially many loops later, which includes a memory allocation and the loop of processing data buffers. Many things may have happened, including the OS using that time to swap to different processes so potentially a significant amount of time has passed between the time.
Rather than only reading the values that had arrived during the earlier "is there any data?" query, they have a buffer that allows for at least 1024 bytes as a minimum. Thus even if there were only 32 bytes available during the initial query, if there were more bytes available at the time recv() is called it would pull up to 1024 bytes that are available, rather than reading only part of the data and keeping it queued until the next update to run. They may have benefited from a second test inside the loop to update how many bytes are available to read, but again, that's a bigger design question of the damage done by waiting for data as well as understanding the time between updates.