Basically, a block has a list of operations, and those operations are applied in the order in which they are in the block. If you read the contents of a block, the higher it is, the sooner it's processed.
Then, there are 3 "levels of operations".
- operations at the highest level of abstraction: the "shell" (which is protocol-independent) sees a list of operations (without knowing much about them);
- operations at the protocol level: those implement what the shell sees, and those are ballots, protocol proposals, transactions, originations, etc (I think there are 11 kinds at this time, but it can change with a new protocol);
- "internal operations": a manager operations (which are transactions, originations, reveals, delegation, for now: this could change with a future protocol) contains a list of "internal manager operations" that are basically "manager operations but a bit simpler/lighter" (for instance, an internal manager operation may not contain an internal manager operation) — the list may be empty, and most often is (or was).
If you see it as a tree data structure, then you have to traverse it depth first for it to make sense.
If you have two operations that are conflicting, either they are different operations at the shell level, and so the first one will be included fine, and the second one will fail (so, as you said, you pay some fees but that's about all that happens).
If your two operations are in the same "operation at the shell level", then the second one that fails will cause the first one to be backtracked.
If you need to know if your two operations are in the same operation or not, simply look at the hashes of the operations: if it's one same single hash, then it's one single operation at the shell level, in which case the failing one causes the entire operation to be backtracked or skipped.