When I submit a transaction and post it to a Horizon endpoint what process determines which validator will handle the transaction? Do client apps have any visibility or control over this?
When you started up your horizon endpoint, you specified (I hope :) ) a stellar-core for it to connect to, via the "--stellar-core-url" flag or "STELLAR_CORE_URL" env variable: https://github.com/stellar/go/blob/master/services/horizon/internal/docs/reference/admin.md
Your configuration for stellar-core, however, is what defines how you want your node to validate transactions. You need to define a quorum set that meets your requirements: https://www.stellar.org/developers/stellar-core/software/admin.html
Long and short, you control (as owner of your own node) who you want to trust.
Currently, all client apps I am aware of are hard-coded to use one specific horizon or allows to switch between one public network horizon and one testnet horizon. It is up to client app developers to disclose it to users. Likewise, the same is about a feature to select a specific horizon.
Each Horizon is tied to a specific node to where it submits transactions and from where it receives information. That node will handle the transaction.
Probably, in the future we will see a feature in Horizon that it can communicate with more than one node. In my opinion that has at least one possible gain - cross-validate ledger information to safeguard against the unlikely forking case.