Today the stable-master health indicator reports `yellow` health if it sees the elected master change 4 times in 30 minutes. However, this could be caused by planned activity such as a rolling restart, and in that case we should not consider a sequence of master failovers as a sign of ill health.

I think we can solve this by refining this check to disregard master nodes that have restarted since they were master, or are no longer in the cluster at all. Restarting the master will always trigger a failover, and the stable-master indicator need not worry about whether the node restart was planned or not; separately, unplanned node restarts are definitely a sign of ill health, but that applies whether the node was the elected master or not. Similarly, if a node is no longer in the cluster then either it is no longer running (again, whether that's planned or not is irrelevant to the stable-master indicator) or else it is running and failing to join the cluster (and hence reporting its own ill health).
server/src/main/java/org/elasticsearch/cluster/coordination/MasterHistory.java
return masterHistoryCopy.isEmpty() ? null : masterHistoryCopy.get(masterHistoryCopy.size() - 1).master;
    }
    /**
     * Returns the most recent non-null master seen, or null if there has been no master seen. Only 30 minutes of history is kept. If the
     * most recent master change is more than 30 minutes old and that change was to set the master to null, then null will be returned.
     * @return The most recent non-null master seen, or null if there has been no master seen.
     */
    public @Nullable DiscoveryNode getMostRecentNonNullMaster() {
        List<TimeAndMaster> masterHistoryCopy = getRecentMasterHistory(masterHistory);
        Collections.reverse(masterHistoryCopy);
        for (TimeAndMaster timeAndMaster : masterHistoryCopy) {
            if (timeAndMaster.master != null) {
                return timeAndMaster.master;
            }
        }
        return null;
    }
    /**
     * Returns true if for the life of this MasterHistory (30 minutes) non-null masters have transitioned to null n times.
     * @param n The number of times a non-null master must have switched to null
     * @return True if non-null masters have transitioned to null n or more times.
     */
    public boolean hasMasterGoneNullAtLeastNTimes(int n) {
        return hasMasterGoneNullAtLeastNTimes(getNodes(), n);
    }
    /**
     * Returns true if for the List of master nodes passed in, non-null masters have transitioned to null n times.
     * So for example:
     * node1 -> null is 1 transition to null
     * node1 -> null -> null is 1 transition to null