After investigating the issue further, the problem actually seems to be that each contract type shares the same data nodes, so when Contract Configurator tries to generate another contract of a type, it's changing the value of expressions for all contracts of that type. That's why contracts that were fine when they were generated are suddenly failing their requirements. Having a contract with a random expression in a data node and requirements that use that expression won't work unless the requirements are always satisfied, or only one contract of that type is allowed to be offered at a time.
I have no idea how to fix the underlying problem, but I was able to work around it by modifying ExpressionRequirement to always return true for contracts that are in the offered state. That at least makes the Bases and Stations pack usable.