It works.
The first thing is to filter out malformed transactions and settle on a canonical transaction order all nodes eventually agree on. Transaction order is a critical concern as there can be no consensus about the present state without consensus about the order of the inputs.
To avoid repetition, these posts describe the same process from slightly different viewpoints:
See here: How Ethereum consensus validates same transaction from different miners?
And here: Ethereum fork that implements transaction ordering
What I have read so far implies that each node - miners and non-miners - must execute the software - the contract. How can this possibly work?
Consider this (pseudo) function:
function adder(uint x, uint y) return(uint sum) { return(x+y); }
Let's put (2,2) into it. Do you know what will come back? Me too. You ran it and got 4. I ran it and got 4. Everyone who wants to agree with us or disagree with us needs to run it as well. Of course, we will think anyone who disagrees with 4 is wrong and we will start disregarding their comments.
The "immutable" part of this is the input and the order in which the inputs arrived. Given this, the only possible conclusion a well-functioning node can reach is 4.
Yes, all full nodes and miners run every transaction in the order laid out in the blocks. They reach agreement at block heights. Every properly functioning node agrees on the state at block heights. So, for example, a node that has synced to block 2,000,000 agrees with every other node, in every detail about the correct interpretation of the world at block 2,000,000.
Another node may be way ahead. Say, it's 10 blocks ahead. More precisely, the others are 10 blocks behind. The node that's ahead will have knowledge of recent transactions and that means it's "current" state will be somewhat ahead of the others. That's okay because the others will hear about recent transactions soon. They will reach complete agreement when they catch up.
You might be wondering how it's possible to process transactions with an out-of-sync blockchain state. In summary, they don't. They only submit transactions (via gossip) and hopefully, a miner will pick up the transactions and include in a block. By definition, that block will be in the future. it will be processed, by all nodes, in the context of the block it's included in, not the context of the world state of the node that sent it.
To say that another way, the sending node doesn't shout out "4!" with the expectation that everyone else should agree. It says someone signed a transaction with (2,2) and wants that transaction to mined into a block. When it's mined into a block, the nodes can all agree on the previous state (if it matters), the code to run and the only possible result of that code, in that context.
Consider this not uncommon scenario.
A newbie starts syncing a node but is waaaay behind. The newbie gives a wallet address to someone else who sends some funds. The wallet balance on Etherscan shows the received funds but the newbie's local wallet does not. The node has not caught up to the block with the transaction that increases the newbie's balance. It will get there, eventually.
Any time a node processes a transaction, it does so in the context of all the transactions that came before, according to the blockchain. The best a node can say about a proposed transaction or a state query is the way it looks in the context of the transactions (and state) it already knows about, a.k.a. at a certain block height.
In practical terms reads and changes (transactions) are treated differently. A software client might use callbacks to update a UI or off-chain database as updates are received. The best it can ever know about is the latest block it knows about. It's possible to make displays etc., that update as new information is received (as blocks arrive).
State-changing transactions are always sent to the network and must be included in a block to have any effect. If a node is far behind, it might send a transaction and not be aware of the result until long after everyone else knows, owing to the fact that it needs to catch up to the block where the transaction appeared.
Hope it helps.