Remove the dispatcher prototype.

PiperOrigin-RevId: 966146610
diff --git a/centipede/BUILD b/centipede/BUILD
index d486c85..dcaabf1 100644
--- a/centipede/BUILD
+++ b/centipede/BUILD
@@ -985,21 +985,6 @@
 )
 
 cc_library(
-    name = "dispatcher",
-    srcs = ["dispatcher.cc"],
-    hdrs = ["dispatcher.h"],
-    deps = [
-        ":execution_metadata",
-        ":mutation_data",
-        ":runner_request",
-        ":runner_result",
-        ":shared_memory_blob_sequence",
-        "@abseil-cpp//absl/base:nullability",
-        "@com_google_fuzztest//common:defs",
-    ],
-)
-
-cc_library(
     name = "engine_worker",
     srcs = [
         "engine_worker.cc",
diff --git a/centipede/centipede_callbacks.cc b/centipede/centipede_callbacks.cc
index 1bcb1e3..961e935 100644
--- a/centipede/centipede_callbacks.cc
+++ b/centipede/centipede_callbacks.cc
@@ -614,9 +614,8 @@
         ReadFromLocalFile(failure_signature_path_,
                           batch_result.failure_signature());
       } else {
-        // TODO(xinhaoyuan): Refactor runner to use dispatcher so this branch
-        // can be removed. Crash deduplication assumes that the failure
-        // signature contains no dashes and that it can be used as a file name.
+        // Crash deduplication assumes that the failure signature contains no
+        // dashes and that it can be used as a file name.
         batch_result.failure_signature() =
             Hash(batch_result.failure_description());
       }
diff --git a/centipede/dispatcher.cc b/centipede/dispatcher.cc
deleted file mode 100644
index 3ecb1f0..0000000
--- a/centipede/dispatcher.cc
+++ /dev/null
@@ -1,621 +0,0 @@
-// Copyright 2025 The Centipede Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "./centipede/dispatcher.h"
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <atomic>
-#include <cerrno>
-#include <cstdint>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <optional>
-#include <string>
-#include <string_view>
-#include <utility>
-#include <vector>
-
-#include "absl/base/nullability.h"
-#include "./centipede/execution_metadata.h"
-#include "./centipede/mutation_data.h"
-#include "./centipede/runner_request.h"
-#include "./centipede/runner_result.h"
-#include "./centipede/shared_memory_blob_sequence.h"
-#include "./common/defs.h"
-
-namespace fuzztest::internal {
-
-namespace {
-
-// Logging needs to be signal safe.
-
-struct LogErrNo {};
-struct LogLnSync {};
-
-void DispatcherLog() {}
-
-template <typename T, typename... Rest>
-void DispatcherLog(const T& first, const Rest&... rest) {
-  if constexpr (std::is_same_v<LogErrNo, T>) {
-    auto saved_errno = errno;
-    char err_buf[80];
-    if (strerror_r(saved_errno, err_buf, sizeof(err_buf)) != 0) {
-      constexpr std::string_view kFallbackMsg = "[strerror_r failed]";
-      static_assert(kFallbackMsg.size() < sizeof(err_buf));
-      std::memcpy(err_buf, kFallbackMsg.data(), kFallbackMsg.size());
-      err_buf[kFallbackMsg.size()] = 0;
-    }
-    DispatcherLog(err_buf);
-  } else if constexpr (std::is_same_v<LogLnSync, T>) {
-    write(STDERR_FILENO, "\n", 1);
-    fsync(STDERR_FILENO);
-  } else {
-    std::string_view sv = first;
-    while (!sv.empty()) {
-      const int r = write(STDERR_FILENO, sv.data(), sv.size());
-      if (r <= 0) break;
-      sv = sv.substr(r);
-    }
-  }
-  DispatcherLog(rest...);
-}
-
-inline void DispatcherCheck(bool condition, std::string_view error) {
-  if (!condition) {
-    DispatcherLog(error, LogLnSync{});
-    std::_Exit(1);
-  }
-}
-
-const char* GetDispatcherFlags() {
-  static auto dispatcher_flags = []() -> const char* {
-    // TODO(xinhaoyuan): Rename the env name to FUZZTEST_DISPATCHER_FLAGS.
-    const char* env_flags = std::getenv("CENTIPEDE_RUNNER_FLAGS");
-    if (env_flags == nullptr) return nullptr;
-    const char* result = strdup(env_flags);
-    DispatcherCheck(result != nullptr, "Cannot copy the dispatcher flags");
-    return result;
-  }();
-  return dispatcher_flags;
-}
-
-std::optional<std::string_view> GetDispatcherFlag(
-    const char* absl_nonnull flag_header) {
-  const char* dispatcher_flags = GetDispatcherFlags();
-  if (dispatcher_flags == nullptr) return std::nullopt;
-  // Extract "value" from ":flag=value:"
-  const char* beg = std::strstr(dispatcher_flags, flag_header);
-  if (!beg) return std::nullopt;
-  const char* value_beg = beg + std::strlen(flag_header);
-  const char* value_end = std::strstr(value_beg, ":");
-  if (!value_end) return std::nullopt;
-  return std::string_view{value_beg,
-                          static_cast<size_t>(value_end - value_beg)};
-}
-
-bool HasDispatcherSwitchFlag(const char* absl_nonnull switch_flag) {
-  const char* dispatcher_flags = GetDispatcherFlags();
-  if (dispatcher_flags == nullptr) return false;
-  return std::strstr(dispatcher_flags, switch_flag) != nullptr;
-}
-
-enum class DispatcherAction {
-  kGetBinaryId,
-  kListTests,
-  kTestGetSeeds,
-  kTestMutate,
-  kTestExecute,
-};
-
-constexpr char kDispatcherBinaryIdOutputFlagHeader[] = ":binary_id_output=";
-constexpr char kDispatcherTestNameFlagHeader[] = ":test=";
-constexpr char kDispatcherTestListingPrefixFlagHeader[] =
-    ":test_listing_prefix=";
-constexpr char kDispatcherTestGetSeedsOutputDirFlagHeader[] =
-    ":arg1=";  // TODO: Use better flag names when standardizing the protocol.
-constexpr char kDispatcherFailureDescriptionPathFlagHeader[] =
-    ":failure_description_path=";
-constexpr char kDispatcherFailureSignaturePathFlagHeader[] =
-    ":failure_signature_path=";
-constexpr char kDispatcherInputsBlobSequencePathFlagHeader[] =
-    ":arg1=";  // TODO: Use better flag names when standardizing the protocol.
-constexpr char kDispatcherOutputsBlobSequencePathFlagHeader[] =
-    ":arg2=";  // TODO: Use better flag names when standardizing the protocol.
-
-BlobSequence* GetInputsBlobSequence() {
-  static auto result = []() -> BlobSequence* {
-    if (std::strstr(GetDispatcherFlags(), ":shmem:") == nullptr) {
-      return nullptr;
-    }
-    auto input_path =
-        GetDispatcherFlag(kDispatcherInputsBlobSequencePathFlagHeader);
-    DispatcherCheck(input_path.has_value(), "inputs blob sequence is missing");
-    return new SharedMemoryBlobSequence(std::string(*input_path).c_str());
-  }();
-  return result;
-}
-
-BlobSequence* GetOutputsBlobSequence() {
-  static auto result = []() -> BlobSequence* {
-    if (std::strstr(GetDispatcherFlags(), ":shmem:") == nullptr) {
-      return nullptr;
-    }
-    auto output_path =
-        GetDispatcherFlag(kDispatcherOutputsBlobSequencePathFlagHeader);
-    DispatcherCheck(output_path.has_value(),
-                    "outputs blob sequence is missing");
-    return new SharedMemoryBlobSequence(std::string(*output_path).c_str());
-  }();
-  return result;
-}
-
-DispatcherAction GetDispatcherAction() {
-  static DispatcherAction dispatcher_action = [] {
-    if (HasDispatcherSwitchFlag(":dump_binary_id:")) {
-      return DispatcherAction::kGetBinaryId;
-    }
-    if (HasDispatcherSwitchFlag(":list_tests:")) {
-      return DispatcherAction::kListTests;
-    }
-    if (HasDispatcherSwitchFlag(":dump_seed_inputs:")) {
-      return DispatcherAction::kTestGetSeeds;
-    }
-    auto* inputs_blobseq = GetInputsBlobSequence();
-    DispatcherCheck(inputs_blobseq != nullptr,
-                    "input blob sequence is not found");
-    auto request_type_blob = inputs_blobseq->Read();
-    if (IsMutationRequest(request_type_blob)) {
-      inputs_blobseq->Reset();
-      return DispatcherAction::kTestMutate;
-    }
-    if (IsExecutionRequest(request_type_blob)) {
-      inputs_blobseq->Reset();
-      return DispatcherAction::kTestExecute;
-    }
-    DispatcherCheck(false, "unknown dispatcher action from the flags");
-    // should not reach here.
-    std::abort();
-  }();
-  return dispatcher_action;
-}
-
-template <typename... C>
-void TrySetFileContents(const char* absl_nonnull path, C... contents) {
-  // Needs to be signal-safe.
-  int f = open(path, O_CREAT | O_TRUNC | O_WRONLY, /*mode=*/0660);
-  if (f == -1) {
-    DispatcherLog("cannot open path ", path, ": ", LogErrNo{}, LogLnSync{});
-    return;
-  }
-  ([&] {
-    std::string_view sv = contents;
-    while (!sv.empty()) {
-      const int r = write(f, sv.data(), sv.size());
-      if (r < 0) {
-        DispatcherLog("write() failed on ", path, ": ", LogErrNo{},
-                      LogLnSync{});
-        return false;
-      }
-      if (r == 0) {
-        DispatcherLog("write() on ", path,
-                      " returns 0 unexpectedly. Stopping writing the file.");
-        return false;
-      }
-      sv = sv.substr(r);
-    }
-    return true;
-  }() &&
-   ...);  // NOLINT - stop fighting with auto-fomatting.
-  if (fsync(f) != 0) {
-    DispatcherLog("fsync() failed on ", path, ": ", LogErrNo{}, LogLnSync{});
-  }
-  if (close(f) != 0) {
-    DispatcherLog("close() failed on ", path, ": ", LogErrNo{}, LogLnSync{});
-  }
-}
-
-static std::atomic<bool> in_test_callback = false;
-
-class TestCallbackGuard {
- public:
-  TestCallbackGuard() {
-    DispatcherCheck(!in_test_callback.exchange(true),
-                    "test callback is already activated");
-  }
-
-  ~TestCallbackGuard() { in_test_callback = false; }
-};
-
-void DispatcherDoGetBinaryId(const FuzzTestDispatcherCallbacks& callbacks) {
-  const auto binary_id_output_path =
-      GetDispatcherFlag(kDispatcherBinaryIdOutputFlagHeader);
-  DispatcherCheck(binary_id_output_path.has_value(),
-                  "binary ID output path is not set");
-  std::string binary_id;
-  {
-    TestCallbackGuard guard;
-    binary_id = callbacks.get_binary_id ? callbacks.get_binary_id() : "";
-  }
-  TrySetFileContents(std::string{*binary_id_output_path}.c_str(), binary_id);
-}
-
-void DispatcherDoListTests(const FuzzTestDispatcherCallbacks& callbacks) {
-  DispatcherCheck(callbacks.list_tests != nullptr,
-                  "list_tests callback must be set");
-  TestCallbackGuard guard;
-  callbacks.list_tests();
-}
-
-void DispatcherDoGetSeeds(const FuzzTestDispatcherCallbacks& callbacks) {
-  if (callbacks.get_seeds == nullptr) {
-    return;
-  }
-  TestCallbackGuard guard;
-  callbacks.get_seeds();
-}
-
-int DispatcherDoMutate(const FuzzTestDispatcherCallbacks& callbacks) {
-  auto* inputs_blobseq = GetInputsBlobSequence();
-  auto* outputs_blobseq = GetOutputsBlobSequence();
-  DispatcherCheck(inputs_blobseq != nullptr && outputs_blobseq != nullptr,
-                  "inputs/outputs blob sequences must be specified");
-
-  bool has_mutate = callbacks.mutate != nullptr;
-  if (!MutationResult::WriteHasCustomMutator(has_mutate, *outputs_blobseq)) {
-    std::fprintf(stderr, "Failed to write custom mutator indicator!\n");
-    return EXIT_FAILURE;
-  }
-  if (!has_mutate) {
-    return EXIT_SUCCESS;
-  }
-
-  // Read max_num_mutants.
-  size_t num_mutants = 0;
-  size_t num_inputs = 0;
-  if (!IsMutationRequest(inputs_blobseq->Read())) {
-    std::fprintf(stderr, "Not mutation request!\n");
-    return EXIT_FAILURE;
-  }
-  if (!IsNumMutants(inputs_blobseq->Read(), num_mutants)) {
-    std::fprintf(stderr, "No num mutants\n");
-    return EXIT_FAILURE;
-  }
-  if (!IsNumInputs(inputs_blobseq->Read(), num_inputs)) {
-    std::fprintf(stderr, "No num inputs\n");
-    return EXIT_FAILURE;
-  }
-
-  struct OwningMutateInput {
-    ByteArray data;
-    ExecutionMetadata metadata;
-  };
-  // Note: unclear if we can continue using std::vector (or other STL)
-  // in the runner. But for now use std::vector.
-  //
-  // Collect the inputs into a vector. We copy them instead of using pointers
-  // into shared memory so that the user code doesn't touch the shared memory.
-  std::vector<OwningMutateInput> owning_inputs;
-  owning_inputs.reserve(num_inputs);
-  std::vector<FuzzTestDispatcherInputForMutate> inputs;
-  inputs.reserve(num_inputs);
-  for (size_t i = 0; i < num_inputs; ++i) {
-    // If inputs_blobseq have overflown in the engine, we still want to
-    // handle the first few inputs.
-    ExecutionMetadata metadata;
-    if (!IsExecutionMetadata(inputs_blobseq->Read(), metadata)) {
-      break;
-    }
-    auto blob = inputs_blobseq->Read();
-    if (!IsDataInput(blob)) break;
-    owning_inputs.push_back(
-        OwningMutateInput{/*data=*/ByteArray{blob.data, blob.data + blob.size},
-                          /*metadata=*/std::move(metadata)});
-    inputs.push_back(FuzzTestDispatcherInputForMutate{
-        /*input=*/owning_inputs.back().data.data(),
-        /*input_size=*/owning_inputs.back().data.size(),
-        /*metadata=*/owning_inputs.back().metadata.cmp_data.data(),
-        /*metadata_size=*/owning_inputs.back().metadata.cmp_data.size()});
-  }
-
-  {
-    TestCallbackGuard guard;
-    fprintf(stderr, "calling custom mutator\n");
-    // We ensure that:
-    //  * `inputs` is a valid pointer to an array of
-    //    `FuzzTestDispatcherInputForMutate` objects with length `num_inputs`.
-    //  * Each object of the array contains a valid `input` pointer to
-    //    `input_size` bytes, and a valid `metadata` pointer to `metadata_size`
-    //    bytes.
-    callbacks.mutate(inputs.data(), inputs.size(), num_mutants,
-                     /*shrink=*/0);
-  }
-  return EXIT_SUCCESS;
-}
-
-int DispatcherDoExecute(const FuzzTestDispatcherCallbacks& callbacks) {
-  DispatcherCheck(callbacks.execute != nullptr, "execute callback must be set");
-  auto* inputs_blobseq = GetInputsBlobSequence();
-  auto* outputs_blobseq = GetOutputsBlobSequence();
-  DispatcherCheck(inputs_blobseq != nullptr && outputs_blobseq != nullptr,
-                  "inputs/ouptuts blob sequence must exist");
-
-  size_t num_inputs = 0;
-  DispatcherCheck(IsExecutionRequest(inputs_blobseq->Read()),
-                  "not an execution request");
-  DispatcherCheck(IsNumInputs(inputs_blobseq->Read(), num_inputs),
-                  "failed to read num_inputs");
-
-  for (size_t i = 0; i < num_inputs; i++) {
-    auto blob = inputs_blobseq->Read();
-    if (!blob.IsValid()) return EXIT_SUCCESS;  // no more blobs to read.
-    if (!IsDataInput(blob)) return EXIT_FAILURE;
-
-    // Copy from blob to data so that to not pass the shared memory further.
-    ByteArray data(blob.data, blob.data + blob.size);
-
-    if (!BatchResult::WriteInputBegin(*outputs_blobseq)) {
-      // TODO: This is to follow the previous behavior, but should we abort
-      // here?
-      break;
-    }
-    {
-      TestCallbackGuard guard;
-      // We ensure that `input` is a valid pointer to an array of `size` bytes.
-      callbacks.execute(data.data(), data.size());
-    }
-    if (!BatchResult::WriteInputEnd(*outputs_blobseq)) {
-      // TODO: This is to follow the previous behavior, but should we abort
-      // here?
-      break;
-    }
-  }
-
-  return EXIT_SUCCESS;
-}
-
-void DispatcherEmitFailure(const char* absl_nonnull prefix,
-                           const char* absl_nonnull description,
-                           const char* signature, size_t signature_size) {
-  bool success = false;
-  [[maybe_unused]] static bool write_once = [=, &success] {
-    if (const auto failure_description_path =
-            GetDispatcherFlag(kDispatcherFailureDescriptionPathFlagHeader);
-        failure_description_path.has_value()) {
-      TrySetFileContents(std::string{*failure_description_path}.c_str(), prefix,
-                         description);
-    }
-    if (const auto failure_signature_path =
-            GetDispatcherFlag(kDispatcherFailureSignaturePathFlagHeader);
-        failure_signature_path.has_value()) {
-      TrySetFileContents(std::string{*failure_signature_path}.c_str(),
-                         std::string_view{signature, signature_size});
-    }
-    success = true;
-    return true;
-  }();
-  if (!success) {
-    DispatcherLog("Failed to emit failure ", prefix, description, LogLnSync{});
-  }
-}
-
-}  // namespace
-
-}  // namespace fuzztest::internal
-
-using fuzztest::internal::BatchResult;
-using fuzztest::internal::DispatcherAction;
-using fuzztest::internal::DispatcherCheck;
-using fuzztest::internal::DispatcherDoExecute;
-using fuzztest::internal::DispatcherDoGetBinaryId;
-using fuzztest::internal::DispatcherDoGetSeeds;
-using fuzztest::internal::DispatcherDoListTests;
-using fuzztest::internal::DispatcherDoMutate;
-using fuzztest::internal::DispatcherEmitFailure;
-using fuzztest::internal::GetDispatcherAction;
-using fuzztest::internal::GetDispatcherFlag;
-using fuzztest::internal::GetDispatcherFlags;
-using fuzztest::internal::GetOutputsBlobSequence;
-using fuzztest::internal::HasDispatcherSwitchFlag;
-using fuzztest::internal::in_test_callback;
-using fuzztest::internal::kDispatcherTestGetSeedsOutputDirFlagHeader;
-using fuzztest::internal::kDispatcherTestListingPrefixFlagHeader;
-using fuzztest::internal::kDispatcherTestNameFlagHeader;
-using fuzztest::internal::MutantRef;
-using fuzztest::internal::MutationResult;
-
-int FuzzTestDispatcherIsEnabled() {
-  const char* flags = GetDispatcherFlags();
-  if (flags == nullptr) return 0;
-  fprintf(stderr, "Dispatcher is enabled with flags: %s\n", flags);
-  return 1;
-}
-
-const char* FuzzTestDispatcherGetTestName() {
-  static auto test_name = []() -> const char* {
-    const auto test_name = GetDispatcherFlag(kDispatcherTestNameFlagHeader);
-    if (!test_name.has_value()) return nullptr;
-    return strndup(test_name->data(), test_name->size());
-  }();
-  return test_name;
-}
-
-int FuzzTestDispatcherRun(const FuzzTestDispatcherCallbacks* callbacks) {
-  DispatcherCheck(callbacks != nullptr, "callbacks must be set");
-  if (HasDispatcherSwitchFlag(":dump_configuration:")) {
-    return 0;
-  }
-  switch (GetDispatcherAction()) {
-    case DispatcherAction::kGetBinaryId:
-      DispatcherDoGetBinaryId(*callbacks);
-      break;
-    case DispatcherAction::kListTests:
-      DispatcherDoListTests(*callbacks);
-      break;
-    case DispatcherAction::kTestGetSeeds:
-      DispatcherDoGetSeeds(*callbacks);
-      break;
-    case DispatcherAction::kTestMutate:
-      DispatcherDoMutate(*callbacks);
-      break;
-    case DispatcherAction::kTestExecute:
-      DispatcherDoExecute(*callbacks);
-      break;
-    default:
-      DispatcherCheck(false, "unknown dispatcher action to take");
-  }
-  return 0;
-}
-
-void FuzzTestDispatcherEmitTestName(const char* name) {
-  DispatcherCheck(
-      GetDispatcherAction() == DispatcherAction::kListTests && in_test_callback,
-      "must be called inside test callback for listing tests");
-  static auto test_listing_prefix =
-      GetDispatcherFlag(kDispatcherTestListingPrefixFlagHeader);
-  DispatcherCheck(test_listing_prefix.has_value(),
-                  "test listing path prefix must be set");
-  DispatcherCheck(name != nullptr, "test name must be set");
-  auto test_output_path = std::string{*test_listing_prefix};
-  test_output_path += name;
-  FILE* f = std::fopen(test_output_path.c_str(), "w");
-  if (f == nullptr) {
-    std::perror("FAILURE: fopen()");
-  }
-  std::fclose(f);
-}
-
-void FuzzTestDispatcherEmitSeed(const void* data, size_t size) {
-  DispatcherCheck(GetDispatcherAction() == DispatcherAction::kTestGetSeeds &&
-                      in_test_callback,
-                  "must be called inside test callback for getting seeds");
-  DispatcherCheck(size > 0 && data != nullptr,
-                  "seed must be non-empty with a valid pointer");
-  static size_t seed_index = 0;
-  static const char* output_dir = [] {
-    const auto flag_value =
-        GetDispatcherFlag(kDispatcherTestGetSeedsOutputDirFlagHeader);
-    DispatcherCheck(flag_value.has_value(),
-                    "seeds output path must be specified");
-    const char* result = strndup(flag_value->data(), flag_value->size());
-    DispatcherCheck(result != nullptr, "failed to copy the seeds output path");
-    return result;
-  }();
-  // Cap seed index within 9 digits. If this was triggered, the dumping would
-  // take forever..
-  if (seed_index >= 1000000000) return;
-  char seed_path_buf[PATH_MAX];
-  const size_t num_path_chars =
-      snprintf(seed_path_buf, PATH_MAX, "%s/%09lu", output_dir, seed_index);
-  DispatcherCheck(num_path_chars < PATH_MAX, "seed path reaches PATH_MAX");
-  FILE* output_file = fopen(seed_path_buf, "w");
-  const size_t num_bytes_written = fwrite(data, 1, size, output_file);
-  DispatcherCheck(num_bytes_written == size,
-                  "wrong number of bytes written for seed");
-  fclose(output_file);
-  ++seed_index;
-}
-
-void FuzzTestDispatcherEmitMutant(const void* data, size_t size) {
-  DispatcherCheck(GetDispatcherAction() == DispatcherAction::kTestMutate &&
-                      in_test_callback,
-                  "must be called inside test callback for mutating");
-  DispatcherCheck(size > 0 && data != nullptr,
-                  "mutant must be non-empty with a valid pointer");
-  auto* output = GetOutputsBlobSequence();
-  DispatcherCheck(output != nullptr, "outputs blob sequence must exist");
-  DispatcherCheck(MutationResult::WriteMutant(
-                      MutantRef{{static_cast<const uint8_t*>(data), size},
-                                // TODO(xinhaoyuan): change the dispatcher
-                                // interface to include the origin.
-                                fuzztest::internal::Mutant::kOriginNone},
-                      *output),
-                  "failed to write mutant");
-}
-
-void FuzzTestDispatcherEmitFeedbackAs32BitFeatures(const uint32_t* features,
-                                                   size_t num_features) {
-  DispatcherCheck(GetDispatcherAction() == DispatcherAction::kTestExecute &&
-                      in_test_callback,
-                  "must be called inside test callback of executing");
-  DispatcherCheck(num_features > 0 && features != nullptr,
-                  "feature array must be non-empty with a valid pointer");
-  auto* output = GetOutputsBlobSequence();
-  DispatcherCheck(output != nullptr, "outputs blob sequence must exist");
-  DispatcherCheck(BatchResult::WriteDispatcher32BitFeatures(
-                      features, num_features, *output),
-                  "failed to write feedback");
-}
-
-void FuzzTestDispatcherEmitFeedbackAsRawFeatures(const uint64_t* features,
-                                                 size_t num_features) {
-  DispatcherCheck(GetDispatcherAction() == DispatcherAction::kTestExecute &&
-                      in_test_callback,
-                  "must be called inside test callback of executing");
-  DispatcherCheck(num_features > 0 && features != nullptr,
-                  "feature array must be non-empty with a valid pointer");
-  auto* output = GetOutputsBlobSequence();
-  DispatcherCheck(output != nullptr, "outputs blob sequence must exist");
-  DispatcherCheck(
-      BatchResult::WriteOneFeatureVec(features, num_features, *output),
-      "failed to write feedback");
-}
-
-void FuzzTestDispatcherEmitExecutionMetadata(const void* metadata,
-                                             size_t size) {
-  DispatcherCheck(GetDispatcherAction() == DispatcherAction::kTestExecute &&
-                      in_test_callback,
-                  "must be called inside test callback of executing");
-  DispatcherCheck(size > 0 && metadata != nullptr,
-                  "metadata must be non-empty with a valid pointer");
-  auto* output = GetOutputsBlobSequence();
-  DispatcherCheck(output != nullptr, "outputs blob sequence must exist");
-  DispatcherCheck(BatchResult::WriteMetadata(
-                      {static_cast<const uint8_t*>(metadata), size}, *output),
-                  "failed to write metadata");
-}
-
-void FuzzTestDispatcherEmitInputFailure(const char* description,
-                                        const void* signature,
-                                        size_t signature_size) {
-  DispatcherCheck(GetDispatcherAction() == DispatcherAction::kTestExecute &&
-                      in_test_callback,
-                  "must be called inside test callback for executing");
-  DispatcherCheck((signature == nullptr) == (signature_size == 0),
-                  "violated invariant: signature should be nullptr if and only "
-                  "if signature_size is 0");
-  DispatcherEmitFailure(
-      "INPUT FAILURE: ", description != nullptr ? description : "",
-      reinterpret_cast<const char*>(signature), signature_size);
-}
-
-void FuzzTestDispatcherEmitIgnoredFailure(const char* description) {
-  DispatcherEmitFailure(
-      "IGNORED FAILURE: ", description != nullptr ? description : "",
-      /*signature=*/nullptr, /*signature_size=*/0);
-}
-
-void FuzzTestDispatcherEmitSetupFailure(const char* description) {
-  DispatcherEmitFailure(
-      "SETUP FAILURE: ", description != nullptr ? description : "",
-      /*signature=*/nullptr, /*signature_size=*/0);
-}
-
-void FuzzTestDispatcherEmitSkippedTestFailure(const char* description) {
-  DispatcherEmitFailure(
-      "SKIPPED TEST: ", description != nullptr ? description : "",
-      /*signature=*/nullptr, /*signature_size=*/0);
-}
diff --git a/centipede/dispatcher.h b/centipede/dispatcher.h
deleted file mode 100644
index 536f443..0000000
--- a/centipede/dispatcher.h
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2025 The Centipede Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef THIRD_PARTY_CENTIPEDE_DISPATCHER_H_
-#define THIRD_PARTY_CENTIPEDE_DISPATCHER_H_
-
-// Dispatcher interface.
-//
-// This header needs to be C compatible.
-
-#include <stddef.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Inputs to perform mutations.
-struct FuzzTestDispatcherInputForMutate {
-  const void* input;
-  size_t input_size;
-  const void* metadata;
-  size_t metadata_size;
-};
-
-// Callbacks to be provided by the fuzz testing framework to
-// `FuzzTestDispatcherRun`.
-struct FuzzTestDispatcherCallbacks {
-  // Optional callback to return an ID for the current binary. If not
-  // implemented, the controller will generate a default ID based on the binary
-  // path.
-  const char* (*get_binary_id)();
-  // Callback to emit the list of available tests in the binary using
-  // `FuzzTestDispatcherEmitTestName`.
-  void (*list_tests)();
-  // Callback to emit the seed inputs for a test using
-  // `FuzzTestDispatcherEmitSeed`.
-  void (*get_seeds)();
-  // Optional callback to emit at most `num_mutants` from `inputs` with
-  // `num_inputs` entries using `FuzzTestDispatcherEmitMutant`. `shrink` != 0
-  // means to generate smaller mutants than the inputs used for mutation. If not
-  // implemented, the controller will perform basic string-based mutations.
-  //
-  // TODO: xinhaoyuan - Reconsider mutation interface design instead of
-  // following the existing Centipede/runner protocol.
-  void (*mutate)(const struct FuzzTestDispatcherInputForMutate* inputs,
-                 size_t num_inputs, size_t num_mutants, int shrink);
-  // Callback to execute `input` with `size` bytes. The callback should emit
-  // coverage feedback using `FuzzTestDispatcherEmitFeedback*` functions, and
-  // any metadata for further mutation using
-  // `FuzzTestDispatEmitExecutionMetadata`. In case the input caused a failure,
-  // the callback should emit the failure using
-  // `FuzzTestDispatcherEmitInputFailure`.
-  void (*execute)(const void* input, size_t size);
-};
-
-// Functions provided by the FuzzTest engine.
-
-// Returns 0 if the dispatcher mode is not enabled in the current process; 1 if
-// the dispatcher mode is enabled; other values for unexpected errors.
-int FuzzTestDispatcherIsEnabled();
-
-// All functions below should be called only after `FuzzTestDispatcherIsEnabled`
-// returns 1 in the current process.
-
-// Returns the test name under operation as an unowned, static, and
-// null-terminated string. Returns nullptr if the current process is not
-// operating on a specific test.
-const char* FuzzTestDispatcherGetTestName();
-
-// Give control to the FuzzTest engine to invoke `callbacks`. Returns an exit
-// code for the current process desired by the engine.
-int FuzzTestDispatcherRun(const struct FuzzTestDispatcherCallbacks* callbacks);
-
-// Emits a test name. Must be called from the `list_tests` callback. `name` must
-// be a null-terminated string.
-void FuzzTestDispatcherEmitTestName(const char* name);
-
-// Emits a seed input. Must be called from the `get_seeds` callback. `data` must
-// not be nullptr and `size > 0` must hold.
-void FuzzTestDispatcherEmitSeed(const void* data, size_t size);
-
-// Emits a mutant. Must be called from the `mutate` callback. `data` must not be
-// nullptr and `size > 0` must hold.
-void FuzzTestDispatcherEmitMutant(const void* data, size_t size);
-
-// TODO: b/437901326 - Unify the feedback emission interfaces.
-
-// Emits coverage feedback for the current input as an array of 32-bit features.
-//
-// For each 32-bit feature, the bit [31] is ignored; the 4 bits [30-27]
-// indicate the feature domain for engine prioritization. The remaining 27 bits
-// [26-0] represent the actual 27-bit feature ID in the domain.
-//
-// Must be called from the `execute` callback. `features` must not be nullptr
-// and `num_features > 0` must hold.
-void FuzzTestDispatcherEmitFeedbackAs32BitFeatures(const uint32_t* features,
-                                                   size_t num_features);
-
-// Must only pass here the "raw" features exposed by the sancov runtime.
-//
-// Must be called from the `execute` callback. `features` must not be nullptr
-// and `num_features > 0` must hold.
-void FuzzTestDispatcherEmitFeedbackAsRawFeatures(const uint64_t* features,
-                                                 size_t num_features);
-
-// Emits metadata of the current input as raw bytes. Must be called from
-// the `execute` callback.
-void FuzzTestDispatcherEmitExecutionMetadata(const void* metadata, size_t size);
-
-// Functions for emitting various types of failures. After calling any of these
-// functions, later calls of these functions would have no effect, and the
-// current process should exit after necessary cleanup.
-
-// Emits a failure caused by executing an input. Must be called within the
-// `execute` callback. `description` should be a null-terminated string, or
-// nullptr can be passed for an empty string; `signature` should be nullptr if
-// and only if `signature_size == 0`.
-void FuzzTestDispatcherEmitInputFailure(const char* description,
-                                        const void* signature,
-                                        size_t signature_size);
-
-// Emits a failure that should be ignored (i.e. not affecting the fuzzing
-// workflows). `description` should be a null-terminated string, or nullptr can
-// be passed for an empty string.
-void FuzzTestDispatcherEmitIgnoredFailure(const char* description);
-
-// Emits a failure caused by the test setup. `description` should be a
-// null-terminated string, or nullptr can be passed for an empty string.
-void FuzzTestDispatcherEmitSetupFailure(const char* description);
-
-// Emits a failure due to reasons to skip the entire test. `description` should
-// be a null-terminated string, or nullptr can be passed for an empty string.
-void FuzzTestDispatcherEmitSkippedTestFailure(const char* description);
-
-#ifdef __cplusplus
-}  // extern "C"
-#endif
-
-#endif
diff --git a/centipede/mutation_data.h b/centipede/mutation_data.h
index 4dc0ee5..4b388b4 100644
--- a/centipede/mutation_data.h
+++ b/centipede/mutation_data.h
@@ -66,8 +66,7 @@
 }
 
 // A reference counterpart of `Mutant`. Needed because it can be constructed
-// from std::string and/or by the C-only dispatcher without copying the
-// underlying data.
+// from std::string without copying the underlying data.
 struct MutantRef {
   MutantRef() = default;
 
diff --git a/centipede/runner_result.cc b/centipede/runner_result.cc
index 07b7810..5d447d9 100644
--- a/centipede/runner_result.cc
+++ b/centipede/runner_result.cc
@@ -37,7 +37,6 @@
 
   // Execution result tags.
   kTagFeatures,
-  kTagDispatcher32BitFeatures,
   kTagInputBegin,
   kTagInputEnd,
   kTagStats,
@@ -57,14 +56,6 @@
                         reinterpret_cast<const uint8_t *>(vec)});
 }
 
-bool BatchResult::WriteDispatcher32BitFeatures(const uint32_t *features,
-                                               size_t num_features,
-                                               BlobSequence &blobseq) {
-  return blobseq.Write({kTagDispatcher32BitFeatures,
-                        num_features * sizeof(features[0]),
-                        reinterpret_cast<const uint8_t *>(features)});
-}
-
 bool BatchResult::WriteInputBegin(BlobSequence &blobseq) {
   return blobseq.Write({kTagInputBegin, 0, nullptr});
 }
@@ -135,19 +126,6 @@
       std::memcpy(features.data(), blob.data,
                   features_size * sizeof(feature_t));
     }
-    if (blob.tag == kTagDispatcher32BitFeatures) {
-      if (current_execution_result == nullptr) return false;
-      const size_t size = blob.size / sizeof(uint32_t);
-      std::vector<uint32_t> copied_features;
-      copied_features.resize(size);
-      std::memcpy(copied_features.data(), blob.data, size * sizeof(uint32_t));
-      auto &features = current_execution_result->mutable_features();
-      features.reserve(features.size() + size);
-      for (uint32_t feature : copied_features) {
-        features.push_back((feature & 0x7fffffff) +
-                           feature_domains::kUserDomains[0].begin());
-      }
-    }
   }
   num_outputs_read_ = num_ends;
   return true;
diff --git a/centipede/runner_result.h b/centipede/runner_result.h
index 8266103..c95f020 100644
--- a/centipede/runner_result.h
+++ b/centipede/runner_result.h
@@ -122,17 +122,6 @@
   // When executing N inputs, the runner will call this at most N times.
   static bool WriteOneFeatureVec(const feature_t* vec, size_t size,
                                  BlobSequence& blobseq);
-  // Writes a buffer of 32-bit `features` to `blobseq`.
-  //
-  // This is a temporary API to work with the dispatcher prototype.
-  //
-  // For each 32-bit feature, the bit [31] is ignored; the 4 bits [30-27]
-  // indicate the domain, which are mapped to the Centipede user-defined domain
-  // 0-15; the remaining 27 bits [26-0] represent the actual 27-bit feature ID
-  // in the domain.
-  static bool WriteDispatcher32BitFeatures(const uint32_t* features,
-                                           size_t num_features,
-                                           BlobSequence& blobseq);
   // Writes a special Begin marker before executing an input.
   static bool WriteInputBegin(BlobSequence& blobseq);
   // Writes a special End marker after executing an input.
diff --git a/centipede/runner_result_test.cc b/centipede/runner_result_test.cc
index 20ce433..f8c86cb 100644
--- a/centipede/runner_result_test.cc
+++ b/centipede/runner_result_test.cc
@@ -249,31 +249,6 @@
   EXPECT_FALSE(batch_result.Read(blobseq));
 }
 
-TEST(ExecutionResult, ReadDispatcher32BitFeatures) {
-  auto buffer = std::make_unique<uint8_t[]>(1000);
-  BlobSequence blobseq(buffer.get(), 1000);
-  BatchResult batch_result;
-
-  std::vector<uint32_t> dispatcher_features = {0, 1, 0x7fffffff, 0xffffffff};
-
-  EXPECT_TRUE(BatchResult::WriteInputBegin(blobseq));
-  EXPECT_TRUE(BatchResult::WriteDispatcher32BitFeatures(
-      dispatcher_features.data(), dispatcher_features.size(), blobseq));
-  EXPECT_TRUE(BatchResult::WriteInputEnd(blobseq));
-  blobseq.Reset();
-  batch_result.ClearAndResize(1);
-  EXPECT_TRUE(batch_result.Read(blobseq));
-
-  ASSERT_EQ(batch_result.num_outputs_read(), 1);
-  EXPECT_THAT(batch_result.results()[0].features(),
-              ElementsAre(feature_domains::kUserDomains[0].ConvertToMe(0),
-                          feature_domains::kUserDomains[0].ConvertToMe(1),
-                          feature_domains::kUserDomains[15].ConvertToMe(
-                              feature_domains::Domain::kDomainSize - 1),
-                          feature_domains::kUserDomains[15].ConvertToMe(
-                              feature_domains::Domain::kDomainSize - 1)));
-}
-
 TEST(ExecutionResult, KeepArbitraryBytesFromMetadata) {
   auto buffer = std::make_unique<uint8_t[]>(1000);
   BlobSequence blobseq(buffer.get(), 1000);
diff --git a/centipede/runner_utils.h b/centipede/runner_utils.h
index 1722bfa..4b85afa 100644
--- a/centipede/runner_utils.h
+++ b/centipede/runner_utils.h
@@ -76,7 +76,7 @@
 extern "C" void __lsan_unregister_root_region(const void* p, size_t size);
 
 // Wraps an object of `T` stored as a plain byte array with explicit
-// construction/destruction. Needed for runner/dispatcher related global states
+// construction/destruction. Needed for runner related global states
 // that need extended lifetime. (Alternatively we could using dynamic pointers
 // for them, but that would introduce extra pointer check/dereference on every
 // use.)