Also, this query returns 210 rows instead of the expected 208:
select * from generate_series(1, 1000) fetch first 20.8 percent rows only
this is because fetch first values work with integer and it change fractional number to nearest integer number like select * from generate_series(1, 1000) fetch first 20.3 rows only; is not an error rather it return 20 rows.
As for the design, I think you should put some serious consideration into Andrew Gierth's approach. I would rather see something like that.
I didn't go in that direction because I don’t understand why this approach is inferior to using window function and I am not fully understand on how to implement it.