Juju will use the model constraints set by the user to spin up arm64 machines whenever a new machine is needed, so again, Juju knows what arch should be used.
Case 3
$ juju deploy foo
Here, Juju will spin up a machine but doesn't know ahead of time what the arch will be. But once the arch is known, Juju can then ask for the relevant charm. The fact that Juju defaults up front to "amd64" and doesn't take account of the ultimate target machine arch is a bug IMO. Just because charms used to be arch agnostic and now they are now is not the user's problem to solve, when Juju does ultimately have all the info needed to make the required decision.
To clarify a bit more, consider
Case 1
$ juju add-machine --constraints "arch=arm64"
Machine 2 added.
$ juju deploy foo --to 2
Juju knows that it is an arm64 machine so it should ask charmhub for an arm64 charm and fail early if one doesn't exist.
Case 2
$ juju set-model- constraints "arch=arm64"
$ juju deploy foo
Juju will use the model constraints set by the user to spin up arm64 machines whenever a new machine is needed, so again, Juju knows what arch should be used.
Case 3
$ juju deploy foo
Here, Juju will spin up a machine but doesn't know ahead of time what the arch will be. But once the arch is known, Juju can then ask for the relevant charm. The fact that Juju defaults up front to "amd64" and doesn't take account of the ultimate target machine arch is a bug IMO. Just because charms used to be arch agnostic and now they are now is not the user's problem to solve, when Juju does ultimately have all the info needed to make the required decision.