Users sometimes accidentally auto-bootstrap their nodes into single-node clusters and then try and join them all together later by setting `discovery.seed_hosts` or similar. Elasticsearch doesn't care if discovery points to a few extra nodes so today it reports no problems, but it's frustrating to the user that it doesn't do what they expect it to do and also doesn't indicate why.

It's almost certainly incorrect to have a nontrivial discovery config in a single-node cluster: `discovery.seed_hosts` and `discovery.seed_providers` should both be unset or empty[^1], so this is a strong indicator that the user is trying to form a multi-node cluster incorrectly. We can therefore be more helpful to these users by emitting periodic warnings in a single-node cluster with nontrivial discovery config:

> `This node is a fully-formed single-node cluster with cluster UUID [{clusterUUID}], but [{setting}] is set to [{value}] as if to discover other nodes and form a multi-node cluster. Fully-formed clusters do not attempt to discover other nodes, and nodes with different cluster UUIDs cannot belong to the same cluster. The cluster UUID persists across restarts and can only be changed by deleting the contents of the node's data path(s). Remove the discovery configuration to suppress this message.`

[^1]: it's also (kind of) acceptable if `discovery.seed_hosts` contains just the node's own publish address, or we're using just the `file` provider and `unicast_hosts.txt` contains just the node's own publish address.
server/src/main/java/org/elasticsearch/cluster/coordination/Coordinator.java
assert clusterFormationFailureHelper.isRunning();
            }
        }
    }
    public boolean isInitialConfigurationSet() {
        return getStateForMasterService().getLastAcceptedConfiguration().isEmpty() == false;
    }
    /**
     * Sets the initial configuration to the given {@link VotingConfiguration}. This method is safe to call
     * more than once, as long as the argument to each call is the same.
     *
     * @param votingConfiguration The nodes that should form the initial configuration.
     * @return whether this call successfully set the initial configuration - if false, the cluster has already been bootstrapped.
     */
    public boolean setInitialConfiguration(final VotingConfiguration votingConfiguration) {
        synchronized (mutex) {
            final ClusterState currentState = getStateForMasterService();
            if (isInitialConfigurationSet()) {
                logger.debug("initial configuration already set, ignoring {}", votingConfiguration);
                return false;
            }
            if (getLocalNode().isMasterNode() == false) {
                logger.debug("skip setting initial configuration as local node is not a master-eligible node");
                throw new CoordinationStateRejectedException(
                    "this node is not master-eligible, but cluster bootstrapping can only happen on a master-eligible node"
                );
            }
            if (votingConfiguration.getNodeIds().contains(getLocalNode().getId()) == false) {
                logger.debug("skip setting initial configuration as local node is not part of initial configuration");
                throw new CoordinationStateRejectedException("local node is not part of initial configuration");