In Nix and Guix, you would indeed not specify that X needs package A version 2.4.2. You could see it as X using the 'build recipe' of A as its dependency. So, if you bump the version of A to 2.4.3, then all packages that use A as a dependency will be rebuilt (or substituted from the a binary cache if the Guix/NixOS build infrastructure has already built the updated packages).
These issues (allow updates within limits) are what I understand as the point of dependency resolution, I'm trying to understand how you do without it.
In such a case e.g. nixpkgs makes two attributes: a_1 and a_2 (and alias a to a_2). Packages that still require A 1.x will have a_1 as one of their dependencies, the rest a.
This is avoided as much as possible, but is sometimes necessary. Common examples are Gtk 2 applications or C/C++ applications that can only be built against a Python 2 interpreter.
> you're right in that normally package definitions specify the exact dependencies it the code (they're hardcoded).
I thought that meant that package X might specify a dependency on A version 2.4.2 exactly. So if you want it to use A 2.4.3 instead, a new release of package X would have to be created, specifying 2.4.3.
But I think this is not in fact what you mean? In which case I don't yet understand the system you are describing and what you mean by not doing dependency resolution.