Actions `cluster:admin/repository/analyze/blob` and `cluster:admin/repository/analyze/register` and so on are only invoked via the transport service, they do not need to register as client actions so we can drop the `ActionType` instance. Instead the root `RepositoryAnalyzeAction` should create and register all these transport actions itself. But even the root `RepositoryAnalyzeAction` should not be an `ActionType` derivative, we should just declare an `ActionType` instance directly. Moreover we can use `ActionType#localOnly` since the client action does not run on remote clusters.
x-pack/plugin/snapshot-repo-test-kit/src/main/java/org/elasticsearch/repositories/blobstore/testkit/BlobAnalyzeAction.java
checksumStart = 0L;
                checksumEnd = request.targetLength;
            e {
                checksumStart = randomLongBetween(0L, request.targetLength);
                checksumEnd = randomLongBetween(checksumStart + 1, request.targetLength + 1);
            }
            final ArrayList<DiscoveryNode> nodes = new ArrayList<>(request.nodes); // copy for shuffling purposes
            if (request.readEarly) {
                Collections.shuffle(nodes, random);
                earlyReadNodes = nodes.stream().limit(request.earlyReadNodeCount).collect(Collectors.toList());
            e {
                earlyReadNodes = List.of();
            }
            Collections.shuffle(nodes, random);
            readNodes = nodes.stream().limit(request.readNodeCount).collect(Collectors.toList());
            final ListenableFuture<Collection<NodeResponse>> readsCompleteStep = new ListenableFuture<>();
            readNodesListener = new GroupedActionListener<>(
                earlyReadNodes.size() + readNodes.size(),
                new ThreadedActionListener<>(transportService.getThreadPool().executor(ThreadPool.Names.SNAPSHOT), readsCompleteStep)
            );
            // The order is important in this chain: if writing fails then we may never even start all the reads, and we want to cancel
            // any read tasks that were started, but the reads step only fails after all the reads have completed so there's no need to
            // cancel anything.
            dListener(
                ActionListener.wrap(
                    write1Details -> write2Step.addListener(
                        ActionListener.wrap(
                            write2Details -> readsCompleteStep.addListener(
                                ActionListener.wrap(
                                    responses -> onReadsComplete(responses, write1Details, write2Details),