This idea came to me this weekend (thanks @ogra for the discussion on Friday):
Why instead of considering the boot partition where the “normal” boot kernel resides, and recovery partition where we reboot when we have pending upgrades, we always reboot to recovery from the boot partition initramfs scripts? So we always follow this sequence, either in power on or in reboot:
boot -> recovery -> userdata
The boot partition would contain the scripts for upgrading kernel/core snaps, and will run them if needed. Regardless of whether upgrading or not, it will do a “reboot recovery”.
The recovery partition would do the normal boot process, starting systemd init in userdata partition.
To all effects, boot partition would be a second stage bootloader, and would have exactly the same functionality we have for u-boot and grub. Cases like refreshing the core snap, then powering off instead of rebooting the device, and then powering on, would work smoothly as in uboot/grub.
When upgrading the kernel snap, the partition to refresh would be recovery, and we would not touch the boot partition.
The drawback all this has is obviously a longer boot time, as we are going through bootloader+kernel load+start to initramfs twice. This takes around 30 additional seconds. It is noticeable, but we can assume this in this sort of IoT devices that are not rebooting that often.
The advantage is a sane upgrade process, fulfilling snap promises