My incomplete ruminations are as follows: The simplest picture of this is to imagine your team as a giant pile of hit points and the enemy team as a giant pile of hit points. You guys are gong to swap damage, cc, adjacency adjustment and healing until you drop. The total damage each round serves as a counter on the combat as it ticks towards the enemies total HP. In this light, healing only makes sense if it heals more than the action cost to cast it: if healing word nullifies one round of an enemy's damage, then it's a good call because it didn't cost a damaging action. Similarly, CC only makes sense if it makes your ticker go faster than the enemy ticker -- if it denies more than the action cost to cast it.Although, I am not sure about the tactics (when is it best to simply swing the weapon, to dodge, to help, to disengage, to switch targets triggering an AoO, to defenestrate an opponent).
I mentioned above that the "AI", which is the Encounter battle() method, is a mess of conditional statements for case specific actions. So it might need a fix to be allow more tactical decisions.
I was adding more features as I went and I wasn't expecting this much stuff. I am half considering making a list of available actions (method references like cast_barkskin, but better) and a respective list of assessment methods that would return a value rating the move, so that the top ranked action could be called. The factors affecting the rating could be tweaked random allowing a random walk towards the best strategy. Anyway, that is just crazy talk.
Your resource expenditure should be optimized such that you run out of resources at the end of the last encounter before you restock. You can imagine multiple encounters as a bigger pile of hit points you have to whittle down, with the opportunity to refresh some resources in between. Optimization should be carried out over all available resources: HP, spells, short rest renewables and consumables (presumably prioritizing consumable expenditure way down).