The trouble with even a simple, well-made tool like Ansible is its dynamic DSL. The YAML file is essentially code, but modules like "file" and "apt" written as configuration entries give a declarative feel to it. But they are just procedures that strive to be idempotent, and its YAML file is just a series of procedure calls, sprinkled with some facility for organizing hierarchies and sharing code between them.
YAML the format is also not a great way to encode systems data. Thankfully Ansible has documented the gotchas with its space-indentation and need for explicit quoting in http://docs.ansible.com/ansible/latest/YAMLSyntax.html#gotch.... But that is just an attempt to band-aid over the unsuitability of YAML for this purpose.
Chef's configuration on the other hand can be done in Ruby, but you're still constrained to its DSLs. The shape and structure of Chef's objects can only gleaned by reading reams of documentation, and worse, by running the cookbooks with debug statements.
The problem is compounded when you upgrade these tools and things stop working silently. The community solution for this unsurprisingly is unit tests. I'm still grappling with that idea.
But what if we could write our own provisioning code in Haskell or OCaml/Reason, with library functions that help install packages, returns errors in neat sum types which we can confidently handle and doesn't leave us to worry about the known unknowns that we haven't enumerated and handled, and a compiler with exhaustive pattern matching that helpfully tells us about all the record types and their structure within a fast edit-compile cycle, ...