The flow I want is: a user deploys an upgradeable contract. They upgrade as necessary. At some point in time, they decide to kill the upgradeability of the contract, making it be in a final state forever. He does this (somehow). Then any future calls to upgrade the proxy will fail, even by the owner.
From what I understand the upgrade happens when a txn is sent from the Admin contract to the proxy contract that updates the implementation address to point to a new one. Since the proxy is how we interact with the implementation contract, it seems to me the only way to implement this logic is having some logic in the PROXY contract, such that when this function is called it sets some flag, and any future upgrade calls will fail. This requires some "require" before the Proxy contract sets the new implementation address.