Not sure whether its relevant or not, however upon adding an ANALYSE before the second vacuum the issue has not presented when testing. I have managed 95 cycles thus far.
BEGIN;
CREATE TABLE x (id BIGSERIAL PRIMARY KEY, payload1 VARCHAR, payload2 VARCHAR, payload3 VARCHAR, payload4 BIGINT, payload5 BIGINT);
/* Repeat until 2,000,000 rows are inserted */
INSERT INTO x (id, payload1, payload2, payload3, payload4, payload5) VALUES (random values of varying length/size to force random toast usage);
COMMIT;
VACUUM (ANALYZE, FULL);
BEGIN;
/* Repeat until all 2,000,000 rows are updated */
UPDATE x SET payload1 = , payload2 = , payload3 = , payload4 = , payload5 = ... again random values of varying length/size to force random toast usage
COMMIT;
ANALYZE x; -- <== New analyse here.
VACCUM (ANALYZE, FULL);