Each bot can run a simulation of the other if the circumstances under which they run their opponents are not the same.
For example, JusticeBot does indeed run a simulation of its opponent, but this is not a problem because JusticeBot simulates what the opponent will do against CooperateBot, not against JusticeBot.
Similarly, an agent could run a simulation of its opponent against itself, but with a different history.
Each bot can run a simulation of the other if the circumstances under which they run their opponents are not the same.
For example, JusticeBot does indeed run a simulation of its opponent, but this is not a problem because JusticeBot simulates what the opponent will do against CooperateBot, not against JusticeBot.
Similarly, an agent could run a simulation of its opponent against itself, but with a different history.
But that different history would have to result in not running a further simulation.
Not immediately, but yes, the recursion would eventually need to hit a base case.