As others have mentioned, I find the "limit yourself to 2-4 hours" BS. I can stand up a new http server in 2 hours to implement some API, sure. Adding unit tests, integration tests, a readme, build instructions/scripts, containerizing it, adding detailed comments, linting... generally not possible to do in 4 hours unless you have everything set up before then (I can't use my normal dev tools to do takehomes because they're through my employer). IRL you would generally scope this as a week-long task even for experienced employees.
Maybe if I were unemployed and desperate for a job I'd suffer it, but most places I'm interested in working at ask whiteboard/design problems anyway.
Anyways, just show me the code and we'll discuss it together, don't waste my time making improvement to toy code that will never get used.
There is a risk here for something that even really strong intermediate programmers fall into where they take a very prescriptive approach to programming so they tend to not understand things built from first principles and also tend to overvalue things like future-proofing and abstraction. Since you don't mention any specifics it's easy for people to fill in the blanks here and assume that at least a good portion of the things you refer to are those kinds of things.
In my experience as an interviewer fishing for specific answers is what makes you miss the best engineers.
I used to do this during my peak Dunning-Kruger phase and gave relatively poor marks to an guy who later proved to surpass both me and the rest of the team in every aspect that mattered - even though originally he barely made it through the interview process.
Chiefly, he didn't do things the way we expected because he prioritized.
Are they always worth fixing, regardless how many there are?
Also, you had plenty of time to prepare these and think this through. Someone seeing this for the first time may assume Chesterton's Fence and not change anything despite noticing - assuming it's less important than breaking whatever reason there might have been for doing things this way.
What I'm getting at is that you're not necessarily getting the best engineers, just ones who think like the current you.
It's a mistake and it's likely already costing you.
I gave out one that was sort roman numbers.
I gave out a file that was 1000 lines long. It may contain duplicates. The numbers are all valid, but are not necessarily reduced (e.g. the number 4 may be represented as IV or IIII).
Print out the reduced numbers in sorted order. If both IV and IIII exist in the file, then IV should be printed out twice (in the proper spot of the overall sorted order).
I timed myself doing this from scratch. It took about 1 hour (7:38 pm to 8:48 pm with some thinking and cleaning sporadically afterwards - https://github.com/shagie/RomanSort/commits/master its 6c79654 that has it acceptably working)
One candidate did it very similar to what I had.
Another candidate didn't have runnable code. Because it was only to take about an hour, and their interview was Monday at 10 am, they didn't start it until they got into their place of current employment that morning (they had a full week to work on it). Neither I nor my manager was impressed with that one.
Another candidate put them into an array (because arrays were faster than lists to access), and then wrote a Comparator to take two roman numeral strings and called Arrays.parallelSort() (because that was faster too), and took the String representation of the array and did a replaceAll on the delimiter with a new line and printed that out. It worked, but the code was messy.
There's a couple obvious tests (written unit tests) that I would expect the candidates to think of for their roman number sorting function, and I usually graded the take homes better when there was 1) evidence of testing 2) evidence of smart, appropriate edge case testing, but not having time to write polished tests in 1h isn't necessarily a red flag.
I'm really struggling to find how simple examples like this can demonstrate anything like GP mentioned.