Solving this in the general case is wild, since the *post_define* calls _gen_compound_id which requires the separator to be defined.
post_define is *often* called before any middleware is stood up and the _gen_compound_id is an integral part of the post_define process.
Here's an idea for a solution, you could use something like this - http://stackoverflow.com/questions/835469/extending-pythons-builtin-str - to defer the loading of the id_separator from middleware until the last-last minute. The object used would have to behave like a string in all ways, but until it needs to actually be represented as a str it's just pretending. <-- Half-baked. :/
TW1 used an underscore. The problem is that if you then use an underscore in a widget's ID, it can cause ambiguity. For example, how does "form_grid_first_name" identify its parent ID? The idea of using a colon was to use a character that would not normally be used in a widget ID.
If the issue is about colons confusing CSS selection, then it at least has to be not-a-css-selector...and not a character that a developer would use for multi-word IDs (i.e. underscore, maybe hyphen)...$ is looking like an option...def can't use @%*()<>=+×÷:~ but I'm not sure about whether the old pipe | is another CSS-friendly option...