And even if you do get opam working for a project, it's not at all reproducible and will just randomly break at some point in the future. For instance, I had this in a Dockerfile for one project:
RUN eval $(opam env) && opam install --yes dune=3.7.0
One day the build just randomly broke. Had to replace it with this:
RUN eval $(opam env) && opam install --yes dune=3.19.1
Not a big change, but the fact that this happens at all is just another part of building with OCaml feeling like building on a foundation of sand. Modern languages have at least learned how to make things reproducible with e.g. lockfiles, but OCaml has not.