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/test/java/org/elasticsearch/cluster/coordination/CoordinatorTests.java
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.lessThanOrEqualTo;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.sameInstance;
import static org.hamcrest.Matchers.startsWith;
@TestLogging(reason = "these tests do a lot of log-worthy things but we usually don't care", value = "org.elasticsearch:FATAL")
public class CoordinatorTests extends AbstractCoordinatorTestCase {
    /**
     * This test was added to verify that state recovery is properly reset on a node after it has become master and successfully
     * recovered a state (see {@link GatewayService}). The situation which triggers this with a decent likelihood is as follows:
     * 3 master-eligible nodes (leader, follower1, follower2), the followers are shut down (leader remains), when followers come back
     * one of them becomes leader and publishes first state (with STATE_NOT_RECOVERED_BLOCK) to old leader, which accepts it.
     * Old leader is initiating an election at the same time, and wins election. It becomes leader again, but as it previously
     * successfully completed state recovery, is never reset to a state where state recovery can be retried.
     */
    public void testStateRecoveryResetAfterPreviousLeadership() {
        try (Cluster cluster = new Cluster(3)) {
            cluster.runRandomly();
            cluster.stabilise();
            final ClusterNode leader = cluster.getAnyLeader();
            final ClusterNode follower1 = cluster.getAnyNodeExcept(leader);
            final ClusterNode follower2 = cluster.getAnyNodeExcept(leader, follower1);
            
            for (ClusterNode clusterNode : Arrays.asList(follower1, follower2)) {