+1 for me as well. The ContainerMatcher should not do any direct data access of its own but have the Containers passed in (either directly or indirectly via the repository). In fact, Patrick and I even discussed the possibility of changing the signature to be something like: match(ModuleDescriptor moduleDescriptor, ModuleDeploymentProperties deploymentProperties, Iterable<Container> containers)

FWIW, I prefer keeping strategy interfaces like this to only 1 public method if at all possible (seems like it should be regardless of what we end up doing here).

Two things we should keep in mind with ContainerMatcher in general, both favoring keeping it as passive as possible:
1. Its logic should be 100% unit-testable *without* requiring any external system, such as ZooKeeper.
2. Advanced users may even provide their own ContainerMatcher implementations (hence "Default" in the name of this one), so we need any "contract" to be enforced in the code that calls into the strategy interface methods. This is a perfect example of Open Closed Principle ("open" for extension, but "closed" for modification).