I personally feel that you can divide this problem into two different categories. One is the more “literal” one, in that stuff happens in a different order depending on coordinates. The consequences of this can be seen in command blocks triggering in different orders or that a dropper chain sends an item a different distance when all power on. This is a natural result of the sequential nature of computers and will never quite go away. The focus should therefor be to fix the second category, although my suggestion for a solution would make even the first category more manageable.
Edit: To clarify I don’t mean that the update order is impossible to make in a predictable intuitive way, just that because of how computers work (sequential) it would be difficult without drastically increasing the amount of calculations required. At that point the cost can quickly outweigh the gain. So not impossible, just impractical.
The second category consists of the situation where the update order causes unpredictable inconsistencies in redstone. Quasi-connectivity is the origin of a large part of these and can cause pistons or droppers/dispensers be BUD-ed (typically on falling edge) for seemingly no reason. This should be a priority to fix, as they cause confusion for the player and can often break contraptions. I do believe some of the inconsistencies with how repeaters and comparators handle fast clocks (some cases signal propagation, some cases off and some cases on) could also be put in this category (not sure).
My suggestion to fix this is to create a better-defined order of (redstone) updates. As far as I can logically think the order should be something like this
1) The empowering components. Redstone torches, comparators and repeaters that are tagged for change does that. Affected blocks/components are queued for change.
2) The blocks that becomes strongly powered or looses said state gets updated. Affected blocks/components are tagged for change. If a component like a dropper gets powered at this stage, it only acts like a solid block at this stage and is queued for change as appropriate.
3) Redstone wire gets handled. Queue appropriate components for change.
4) Weakly powered blocks updates.
5) All components that cause block updates (that have not already been checked) should be noted, and all components that are updated should be queued for execution (but not actually done yet). Do this recursively so that everything is queued for execution.
6) Execute the behaviour of all the components queued for action. As it is only at/after this stage pistons and dispensers can influence the world, no consequences of those action should have been handled.
7) If the world has been influenced (pistons moving a powered block etc), repeat the steps. They should keep repeating until they are done, as things like instant (falling edge piston) signals requires multiple loops. The game should already be free of potential closed loops.
Edit: To clarify the only two blocks that can change the state of the world in such a way that I can see are dispensers (can place certain blocks, blocking redstone wire or getting strongly powered) and pistons (moving a powered block, moving a block blocking redstone wire over an ledge). The dispenser uses 2 redstone ticks to activate and can therefore not be looped this tick. The piston starts moving the same tick, and moving blocks loses their ability block or power redstone, and therefore instantly cause a change. As I understand it the blocks would only return to solid blocks in a future tick and can therefore not be looped. So, while long chains are possible, loops should be impossible. Exactly where in the process the dispensers place the block or the moved block turns solid should also be considered. Note that I included this last step to conserve 0-tick behaviour. If it is a bug rather than a quirk (like quasi-connectivity), simply dropping step 7 should remove all 0-tick behaviour I can think of as the change only gets registered the next tick.
I believe this loop would keep the behaviour more constant (no variable BUDing) while staying mostly the same (for example 0 tick pistons and pulses should still work).
In addition, I believe it is sensible to instead of activating all components in the order they where detected, to separate the different components into their own queues (one queue for droppers, one queue for trapdoors, one queue for both piston types). While the update order within each queue is the same as it is now (if only there was components of that type), but create a known hierarchy between the different. For example, fire all droppers before any dispensers fire. The result of this addition would be a much clearer update order, something that partially fixes the first category problem. It would also lower the skill celling for working with these timings benefitting casual(ish) players. Note that the hierarchy and content of the queues is important and should be thoroughly considered. For example, droppers should activate before dispensers as droppers can be used to move an item and using it the same tick. Likewise, both pistons types should be in the same queue to conserve loads of currently vital behaviour. And depending on if pistons are prior to dispensers the behaviour could differ, although if the steps mentioned above are followed using pistons to (de)power components in different loops the order can be accurately manipulated.
To implement this in the code I imagine "all" you need is to fill different FIFO queues with blocks/wire/components to power. If something powers something handled in a different step, put it in the appropriate queue. A wire on top of a dispenser should queue it in both the ‘weakly powered block queue’ to see if something reacts to that, and the ‘dispensers to be activated queue’. Redstone wire powering redstone wire are both on the same step, and don’t need to be queued. The idea is to have a ‘detect all, then execute all’ approach instead of the ‘detect execute repeat’ approach it seemingly has now (could be completely wrong there. Don’t know any Java nor the inner workings of the game).
Although some of the more advanced contraption that are orientation dependent probably would break, a more well-defined update order would make it easier and more predictable to redesign most of them. It would remove inconsistencies and make the process more beginner friendly, all while staying mostly the same as now. And lastly it would offer more manipulation of chain of events for advanced players opening new possibilities. So, in total something I think would be worth implementing.
TL; DR: This problem has a “everything happens, but in a location dependent order” part and a “things can get BUD-ed dependent on location” part. I personally think the BUD part should be a high priority to fix. My suggestion to do that is to have a component-dependent update order. First things that gives redstone power (repeaters, redstone torch, comparator), then strongly powered blocks, then redstone wire, weakly powered blocks, and lastly activate the components. If something changed the same tick (e.g. piston moving powered blocks) repeat. The different components with behaviour should have a strict order of activation (like all droppers activate before any dispensers do. Order among in a single category can have a similar order as now).
I hope this ramble could be of some help or inspiration, and don’t only make sense in my head.
Edit: Some grammar fixes (although i still think redstone has its tics as well 😛)
Response to the comments from @(Fabian Röling) and @(Pegasus Epsilon)
1) To clarify I don’t mean that the update order is impossible to make in a predictable intuitive way, just that because of how computers work (sequential) it would be incredibly difficult without drastically increasing the amount of calculations required. At that point the cost can quickly outweigh the gain. So not impossible, just impractical.
2) As I understand the game it should be impossible to create loops in the last step. The only two blocks that can change the state of the world in such a way that I can see are dispensers (can place certain blocks, blocking redstone wire or getting strongly powered) and pistons (moving a powered block, moving a block blocking redstone wire over an ledge). The dispenser uses 2 redstone ticks to activate and can therefore not be looped this tick. The piston starts moving the same tick, and moving blocks loses their ability block or power redstone, and therefore instantly cause a change. As I understand it the blocks would only return to solid blocks in a future tick and can therefore not be looped. So, while long chains are possible, loops should be impossible. Exactly where in the process the dispensers place the block or the moved block turns solid should also be considered.
3) I thought 0-tick pulses was a quirk (like quasi-connectivity) rather than a bug, and specifically included the last step to conserve it. Simply removing that step should remove all the cases of 0-ticks that I can think of, because affected wire/components only would ‘see’ that something had changed the next tick.
I updated the main text to clarify.
Edit: Some grammar fixes (although i still think redstone has its tics as well 😛)