For the memory case allowing a range with no special handling of 0/-1 is sufficient to express most policies that people would want to use. I think the two common use case x..y where x > 0 to specify a range bounded on both ends and 1..y to express an upper bound. You'd need special handling to express x..INF and it make the behaviour of 0..x a bit weird, but the behaviour is simple at least.
I don't think we need two special values to express "infinite memory' but I think cleaning it up would be a breaking change. IMO -1 should be the special value because 0 is sometimes a reasonable value, e.g. for scratch_limit. However a lot of older query options limit mem_limit used "0" and have that documented as the way to specify "unlimited".
I think that's a good point about enums since there's multiple ways to specify the same value. I don't see an immediate need for that so maybe it's ok to ignore that case for now.