Oh, that's a great question, I missed a critical piece of information in my post: the target is a miniCore ATmega, and the MiniCore board manager is adding a menu with the serial speed.
The issue is probably specific to using a MiniCore board behind an ArduinoISP board.
Sorry, my "solution" did work, but doesn't work any more, and I probably had too many things changing in my tests. I don't even understand how it could do anything, given that changing the baud speed is not changing the speed at which avrdude is talking to arduinoISP.
I just want to add two things for people reading this:
I incorrectly assumed that the values from the error messages (0x15, 0x14, 0x14, 0x02, 0x10) were signals interpreted at a wrong speed. It's not the case. These values are perfectly normal, 0x15 means NO_SYNC, that's how the protocol gets back into sync: the software is supposed to ignore them, and get to the next bytes which are the real answers. Except that avrdude takes them as invalid responses, and sends another request, keeping being out of sync (see timeline below).
Commenting the line sending NO_SYNC in arduinoISP when something wrong happens (in the default: case) ends up fixing things: if avrdude doesn't ignore NO_SYNC, we can just send nothing, that's going to be ignored for sure.
You can see the NO_SYNC from a previous attempt, then the requests (30 20), correctly answered with (14 10), but avrdude sees all that as wrong:
Warning: attempt 1 of 10: not in sync: resp=0x15
Warning: attempt 2 of 10: not in sync: resp=0x15
Error: protocol expects OK byte 0x10 but got 0x14
Error: protocol expects sync byte 0x14 but got 0x02
Error: protocol expects sync byte 0x14 but got 0x10