From 459abbec5af097a74cbf578fcd5278492e48c065 Mon Sep 17 00:00:00 2001
From: "Mark D. Roth" <roth@google.com>
Date: Wed, 24 Apr 2024 10:22:29 -0700
Subject: [PATCH 1/5] [channelz] add synchronization for channel traces
 (#36434)

Fixes #36409.

Also do a bit of code cleanup.

Closes #36434

COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/36434 from markdroth:channelz_crash_fix c9ea4ecdaa511946966d10fe56fc28d9b54a2c2d
PiperOrigin-RevId: 627771370
---
 src/core/channelz/channel_trace.cc       | 111 +++++++++++------------
 src/core/channelz/channel_trace.h        |  31 ++++---
 test/core/channelz/channel_trace_test.cc |  24 +++++
 3 files changed, 94 insertions(+), 72 deletions(-)

diff --git a/src/core/channelz/channel_trace.cc b/src/core/channelz/channel_trace.cc
index ac8be425c61..60b0a937c96 100644
--- a/src/core/channelz/channel_trace.cc
+++ b/src/core/channelz/channel_trace.cc
@@ -36,37 +36,68 @@
 namespace grpc_core {
 namespace channelz {
 
+//
+// ChannelTrace::TraceEvent
+//
+
 ChannelTrace::TraceEvent::TraceEvent(Severity severity, const grpc_slice& data,
                                      RefCountedPtr<BaseNode> referenced_entity)
-    : severity_(severity),
+    : timestamp_(Timestamp::Now().as_timespec(GPR_CLOCK_REALTIME)),
+      severity_(severity),
       data_(data),
-      timestamp_(Timestamp::Now().as_timespec(GPR_CLOCK_REALTIME)),
-      next_(nullptr),
-      referenced_entity_(std::move(referenced_entity)),
-      memory_usage_(sizeof(TraceEvent) + grpc_slice_memory_usage(data)) {}
+      memory_usage_(sizeof(TraceEvent) + grpc_slice_memory_usage(data)),
+      referenced_entity_(std::move(referenced_entity)) {}
 
 ChannelTrace::TraceEvent::TraceEvent(Severity severity, const grpc_slice& data)
-    : severity_(severity),
-      data_(data),
-      timestamp_(Timestamp::Now().as_timespec(GPR_CLOCK_REALTIME)),
-      next_(nullptr),
-      memory_usage_(sizeof(TraceEvent) + grpc_slice_memory_usage(data)) {}
+    : TraceEvent(severity, data, nullptr) {}
 
 ChannelTrace::TraceEvent::~TraceEvent() { CSliceUnref(data_); }
 
-ChannelTrace::ChannelTrace(size_t max_event_memory)
-    : num_events_logged_(0),
-      event_list_memory_usage_(0),
-      max_event_memory_(max_event_memory),
-      head_trace_(nullptr),
-      tail_trace_(nullptr) {
-  if (max_event_memory_ == 0) {
-    return;  // tracing is disabled if max_event_memory_ == 0
+namespace {
+
+const char* SeverityString(ChannelTrace::Severity severity) {
+  switch (severity) {
+    case ChannelTrace::Severity::Info:
+      return "CT_INFO";
+    case ChannelTrace::Severity::Warning:
+      return "CT_WARNING";
+    case ChannelTrace::Severity::Error:
+      return "CT_ERROR";
+    default:
+      GPR_UNREACHABLE_CODE(return "CT_UNKNOWN");
+  }
+}
+
+}  // anonymous namespace
+
+Json ChannelTrace::TraceEvent::RenderTraceEvent() const {
+  char* description = grpc_slice_to_c_string(data_);
+  Json::Object object = {
+      {"description", Json::FromString(description)},
+      {"severity", Json::FromString(SeverityString(severity_))},
+      {"timestamp", Json::FromString(gpr_format_timespec(timestamp_))},
+  };
+  gpr_free(description);
+  if (referenced_entity_ != nullptr) {
+    const bool is_channel =
+        (referenced_entity_->type() == BaseNode::EntityType::kTopLevelChannel ||
+         referenced_entity_->type() == BaseNode::EntityType::kInternalChannel);
+    object[is_channel ? "channelRef" : "subchannelRef"] = Json::FromObject({
+        {(is_channel ? "channelId" : "subchannelId"),
+         Json::FromString(absl::StrCat(referenced_entity_->uuid()))},
+    });
   }
-  gpr_mu_init(&tracer_mu_);
-  time_created_ = Timestamp::Now().as_timespec(GPR_CLOCK_REALTIME);
+  return Json::FromObject(std::move(object));
 }
 
+//
+// ChannelTrace
+//
+
+ChannelTrace::ChannelTrace(size_t max_event_memory)
+    : max_event_memory_(max_event_memory),
+      time_created_(Timestamp::Now().as_timespec(GPR_CLOCK_REALTIME)) {}
+
 ChannelTrace::~ChannelTrace() {
   if (max_event_memory_ == 0) {
     return;  // tracing is disabled if max_event_memory_ == 0
@@ -77,10 +108,10 @@ ChannelTrace::~ChannelTrace() {
     it = it->next();
     delete to_free;
   }
-  gpr_mu_destroy(&tracer_mu_);
 }
 
 void ChannelTrace::AddTraceEventHelper(TraceEvent* new_trace_event) {
+  MutexLock lock(&mu_);
   ++num_events_logged_;
   // first event case
   if (head_trace_ == nullptr) {
@@ -121,43 +152,6 @@ void ChannelTrace::AddTraceEventWithReference(
       new TraceEvent(severity, data, std::move(referenced_entity)));
 }
 
-namespace {
-
-const char* severity_string(ChannelTrace::Severity severity) {
-  switch (severity) {
-    case ChannelTrace::Severity::Info:
-      return "CT_INFO";
-    case ChannelTrace::Severity::Warning:
-      return "CT_WARNING";
-    case ChannelTrace::Severity::Error:
-      return "CT_ERROR";
-    default:
-      GPR_UNREACHABLE_CODE(return "CT_UNKNOWN");
-  }
-}
-
-}  // anonymous namespace
-
-Json ChannelTrace::TraceEvent::RenderTraceEvent() const {
-  char* description = grpc_slice_to_c_string(data_);
-  Json::Object object = {
-      {"description", Json::FromString(description)},
-      {"severity", Json::FromString(severity_string(severity_))},
-      {"timestamp", Json::FromString(gpr_format_timespec(timestamp_))},
-  };
-  gpr_free(description);
-  if (referenced_entity_ != nullptr) {
-    const bool is_channel =
-        (referenced_entity_->type() == BaseNode::EntityType::kTopLevelChannel ||
-         referenced_entity_->type() == BaseNode::EntityType::kInternalChannel);
-    object[is_channel ? "channelRef" : "subchannelRef"] = Json::FromObject({
-        {(is_channel ? "channelId" : "subchannelId"),
-         Json::FromString(absl::StrCat(referenced_entity_->uuid()))},
-    });
-  }
-  return Json::FromObject(std::move(object));
-}
-
 Json ChannelTrace::RenderJson() const {
   // Tracing is disabled if max_event_memory_ == 0.
   if (max_event_memory_ == 0) {
@@ -167,6 +161,7 @@ Json ChannelTrace::RenderJson() const {
       {"creationTimestamp",
        Json::FromString(gpr_format_timespec(time_created_))},
   };
+  MutexLock lock(&mu_);
   if (num_events_logged_ > 0) {
     object["numEventsLogged"] =
         Json::FromString(absl::StrCat(num_events_logged_));
diff --git a/src/core/channelz/channel_trace.h b/src/core/channelz/channel_trace.h
index 0b8e1bc7216..b0465b5861a 100644
--- a/src/core/channelz/channel_trace.h
+++ b/src/core/channelz/channel_trace.h
@@ -22,12 +22,14 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "absl/base/thread_annotations.h"
+
 #include <grpc/slice.h>
 #include <grpc/support/port_platform.h>
-#include <grpc/support/sync.h>
 #include <grpc/support/time.h>
 
 #include "src/core/lib/gprpp/ref_counted_ptr.h"
+#include "src/core/lib/gprpp/sync.h"
 #include "src/core/lib/json/json.h"
 
 namespace grpc_core {
@@ -110,25 +112,26 @@ class ChannelTrace {
     size_t memory_usage() const { return memory_usage_; }
 
    private:
-    Severity severity_;
-    grpc_slice data_;
-    gpr_timespec timestamp_;
-    TraceEvent* next_;
+    const gpr_timespec timestamp_;
+    const Severity severity_;
+    const grpc_slice data_;
+    const size_t memory_usage_;
     // the tracer object for the (sub)channel that this trace event refers to.
-    RefCountedPtr<BaseNode> referenced_entity_;
-    size_t memory_usage_;
+    const RefCountedPtr<BaseNode> referenced_entity_;
+    TraceEvent* next_ = nullptr;
   };  // TraceEvent
 
   // Internal helper to add and link in a trace event
   void AddTraceEventHelper(TraceEvent* new_trace_event);
 
-  gpr_mu tracer_mu_;
-  uint64_t num_events_logged_;
-  size_t event_list_memory_usage_;
-  size_t max_event_memory_;
-  TraceEvent* head_trace_;
-  TraceEvent* tail_trace_;
-  gpr_timespec time_created_;
+  const size_t max_event_memory_;
+  const gpr_timespec time_created_;
+
+  mutable Mutex mu_;
+  uint64_t num_events_logged_ ABSL_GUARDED_BY(mu_) = 0;
+  size_t event_list_memory_usage_ ABSL_GUARDED_BY(mu_) = 0;
+  TraceEvent* head_trace_ ABSL_GUARDED_BY(mu_) = nullptr;
+  TraceEvent* tail_trace_ ABSL_GUARDED_BY(mu_) = nullptr;
 };
 
 }  // namespace channelz
diff --git a/test/core/channelz/channel_trace_test.cc b/test/core/channelz/channel_trace_test.cc
index 04eb892927a..817fd30f687 100644
--- a/test/core/channelz/channel_trace_test.cc
+++ b/test/core/channelz/channel_trace_test.cc
@@ -21,7 +21,9 @@
 #include <stdlib.h>
 
 #include <string>
+#include <thread>
 
+#include "absl/synchronization/notification.h"
 #include "gtest/gtest.h"
 
 #include <grpc/credentials.h>
@@ -317,6 +319,28 @@ TEST(ChannelTracerTest, TestTotalEviction) {
   ValidateChannelTraceCustom(&tracer, kNumEvents + 1, 0);
 }
 
+// Tests that the code is thread-safe.
+TEST(ChannelTracerTest, ThreadSafety) {
+  ExecCtx exec_ctx;
+  ChannelTrace tracer(kEventListMemoryLimit);
+  absl::Notification done;
+  std::vector<std::unique_ptr<std::thread>> threads;
+  for (size_t i = 0; i < 10; ++i) {
+    threads.push_back(std::make_unique<std::thread>([&]() {
+      do {
+        AddSimpleTrace(&tracer);
+      } while (!done.HasBeenNotified());
+    }));
+  }
+  for (size_t i = 0; i < 10; ++i) {
+    tracer.RenderJson();
+  }
+  done.Notify();
+  for (const auto& thd : threads) {
+    thd->join();
+  }
+}
+
 }  // namespace testing
 }  // namespace channelz
 }  // namespace grpc_core

From d52779da52dad491b5779e74e0140c77e8426160 Mon Sep 17 00:00:00 2001
From: Craig Tiller <ctiller@google.com>
Date: Wed, 24 Apr 2024 11:00:01 -0700
Subject: [PATCH 2/5] [call-v3] Interception chain (#36414)

Introduce the interception chain type.
Also introduces the real call-v3 call spine based atop CallFilters.

Closes #36414

COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/36414 from ctiller:interception-chain 90c8e969738c1c999db7257c2c24aeb382818c70
PiperOrigin-RevId: 627784183
---
 BUILD                                         |   2 +-
 CMakeLists.txt                                | 307 ++++++++-
 Makefile                                      |   2 +-
 Package.swift                                 |   4 +-
 build_autogenerated.yaml                      | 606 +++++++++++++++++-
 config.m4                                     |   2 +-
 config.w32                                    |   2 +-
 gRPC-C++.podspec                              |   4 +-
 gRPC-Core.podspec                             |   6 +-
 grpc.gemspec                                  |   4 +-
 package.xml                                   |   4 +-
 src/core/BUILD                                |  36 +-
 src/core/lib/channel/promise_based_filter.h   |  41 +-
 src/core/lib/promise/detail/seq_state.h       | 360 +++++------
 src/core/lib/promise/for_each.h               |  19 +-
 src/core/lib/promise/party.cc                 |  12 +-
 src/core/lib/surface/call.cc                  |  13 +
 src/core/lib/surface/legacy_channel.h         |   2 +-
 ...e_estimator.cc => call_arena_allocator.cc} |   2 +-
 ...ize_estimator.h => call_arena_allocator.h} |  27 +-
 src/core/lib/transport/call_destination.h     |  31 +-
 src/core/lib/transport/call_filters.cc        |  21 +-
 src/core/lib/transport/call_filters.h         | 154 +++--
 src/core/lib/transport/call_spine.cc          |  13 +-
 src/core/lib/transport/call_spine.h           | 227 +++++--
 src/core/lib/transport/interception_chain.cc  | 156 +++++
 src/core/lib/transport/interception_chain.h   | 225 +++++++
 src/python/grpcio/grpc_core_dependencies.py   |   2 +-
 test/core/promise/BUILD                       |  10 +
 test/core/promise/observable_test.cc          |  29 +-
 test/core/promise/poll_matcher.h              |  60 ++
 test/core/transport/BUILD                     |  18 +
 test/core/transport/call_filters_test.cc      |  30 +-
 .../client_transport_error_test.cc            |  57 +-
 .../chaotic_good/client_transport_test.cc     |  22 +-
 .../chaotic_good/server_transport_test.cc     |   8 +-
 .../transport/chaotic_good/transport_test.h   |  21 +-
 .../core/transport/interception_chain_test.cc | 406 ++++++++++++
 test/core/transport/test_suite/test.cc        |  10 +-
 test/core/transport/test_suite/test.h         |  29 +-
 tools/doxygen/Doxyfile.c++.internal           |   4 +-
 tools/doxygen/Doxyfile.core.internal          |   4 +-
 tools/run_tests/generated/tests.json          |  24 +
 43 files changed, 2538 insertions(+), 478 deletions(-)
 rename src/core/lib/transport/{call_size_estimator.cc => call_arena_allocator.cc} (96%)
 rename src/core/lib/transport/{call_size_estimator.h => call_arena_allocator.h} (65%)
 create mode 100644 src/core/lib/transport/interception_chain.cc
 create mode 100644 src/core/lib/transport/interception_chain.h
 create mode 100644 test/core/promise/poll_matcher.h
 create mode 100644 test/core/transport/interception_chain_test.cc

diff --git a/BUILD b/BUILD
index ae8e518fffd..406e42294d8 100644
--- a/BUILD
+++ b/BUILD
@@ -1796,7 +1796,7 @@ grpc_cc_library(
         "ref_counted_ptr",
         "stats",
         "//src/core:arena",
-        "//src/core:call_size_estimator",
+        "//src/core:call_arena_allocator",
         "//src/core:channel_args",
         "//src/core:channel_fwd",
         "//src/core:channel_init",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f34190ef47f..f227cddcb6a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1169,6 +1169,7 @@ if(gRPC_BUILD_TESTS)
   add_dependencies(buildtests_cxx insecure_security_connector_test)
   add_dependencies(buildtests_cxx inter_activity_latch_test)
   add_dependencies(buildtests_cxx inter_activity_pipe_test)
+  add_dependencies(buildtests_cxx interception_chain_test)
   add_dependencies(buildtests_cxx interceptor_list_test)
   add_dependencies(buildtests_cxx interop_client)
   add_dependencies(buildtests_cxx interop_server)
@@ -2514,9 +2515,9 @@ add_library(grpc
   src/core/lib/surface/wait_for_cq_end_op.cc
   src/core/lib/transport/batch_builder.cc
   src/core/lib/transport/bdp_estimator.cc
+  src/core/lib/transport/call_arena_allocator.cc
   src/core/lib/transport/call_filters.cc
   src/core/lib/transport/call_final_info.cc
-  src/core/lib/transport/call_size_estimator.cc
   src/core/lib/transport/call_spine.cc
   src/core/lib/transport/connectivity_state.cc
   src/core/lib/transport/endpoint_info_handshaker.cc
@@ -3240,9 +3241,9 @@ add_library(grpc_unsecure
   src/core/lib/surface/wait_for_cq_end_op.cc
   src/core/lib/transport/batch_builder.cc
   src/core/lib/transport/bdp_estimator.cc
+  src/core/lib/transport/call_arena_allocator.cc
   src/core/lib/transport/call_filters.cc
   src/core/lib/transport/call_final_info.cc
-  src/core/lib/transport/call_size_estimator.cc
   src/core/lib/transport/call_spine.cc
   src/core/lib/transport/connectivity_state.cc
   src/core/lib/transport/endpoint_info_handshaker.cc
@@ -5349,6 +5350,7 @@ add_library(grpc_authorization_provider
   src/core/lib/surface/version.cc
   src/core/lib/surface/wait_for_cq_end_op.cc
   src/core/lib/transport/batch_builder.cc
+  src/core/lib/transport/call_arena_allocator.cc
   src/core/lib/transport/call_filters.cc
   src/core/lib/transport/call_final_info.cc
   src/core/lib/transport/call_spine.cc
@@ -17784,6 +17786,307 @@ target_link_libraries(inter_activity_pipe_test
 )
 
 
+endif()
+if(gRPC_BUILD_TESTS)
+
+add_executable(interception_chain_test
+  src/core/channelz/channel_trace.cc
+  src/core/channelz/channelz.cc
+  src/core/channelz/channelz_registry.cc
+  src/core/ext/upb-gen/google/protobuf/any.upb_minitable.c
+  src/core/ext/upb-gen/google/rpc/status.upb_minitable.c
+  src/core/ext/upb-gen/src/proto/grpc/gcp/altscontext.upb_minitable.c
+  src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb_minitable.c
+  src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb_minitable.c
+  src/core/lib/address_utils/parse_address.cc
+  src/core/lib/address_utils/sockaddr_utils.cc
+  src/core/lib/backoff/backoff.cc
+  src/core/lib/channel/call_tracer.cc
+  src/core/lib/channel/channel_args.cc
+  src/core/lib/channel/channel_args_preconditioning.cc
+  src/core/lib/channel/channel_stack.cc
+  src/core/lib/channel/channel_stack_builder.cc
+  src/core/lib/channel/channel_stack_builder_impl.cc
+  src/core/lib/channel/channel_stack_trace.cc
+  src/core/lib/channel/connected_channel.cc
+  src/core/lib/channel/metrics.cc
+  src/core/lib/channel/promise_based_filter.cc
+  src/core/lib/channel/status_util.cc
+  src/core/lib/compression/compression.cc
+  src/core/lib/compression/compression_internal.cc
+  src/core/lib/compression/message_compress.cc
+  src/core/lib/config/core_configuration.cc
+  src/core/lib/debug/event_log.cc
+  src/core/lib/debug/histogram_view.cc
+  src/core/lib/debug/stats.cc
+  src/core/lib/debug/stats_data.cc
+  src/core/lib/debug/trace.cc
+  src/core/lib/event_engine/ares_resolver.cc
+  src/core/lib/event_engine/cf_engine/cf_engine.cc
+  src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc
+  src/core/lib/event_engine/cf_engine/dns_service_resolver.cc
+  src/core/lib/event_engine/channel_args_endpoint_config.cc
+  src/core/lib/event_engine/default_event_engine.cc
+  src/core/lib/event_engine/default_event_engine_factory.cc
+  src/core/lib/event_engine/event_engine.cc
+  src/core/lib/event_engine/forkable.cc
+  src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc
+  src/core/lib/event_engine/posix_engine/ev_poll_posix.cc
+  src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc
+  src/core/lib/event_engine/posix_engine/internal_errqueue.cc
+  src/core/lib/event_engine/posix_engine/lockfree_event.cc
+  src/core/lib/event_engine/posix_engine/native_posix_dns_resolver.cc
+  src/core/lib/event_engine/posix_engine/posix_endpoint.cc
+  src/core/lib/event_engine/posix_engine/posix_engine.cc
+  src/core/lib/event_engine/posix_engine/posix_engine_listener.cc
+  src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.cc
+  src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc
+  src/core/lib/event_engine/posix_engine/timer.cc
+  src/core/lib/event_engine/posix_engine/timer_heap.cc
+  src/core/lib/event_engine/posix_engine/timer_manager.cc
+  src/core/lib/event_engine/posix_engine/traced_buffer_list.cc
+  src/core/lib/event_engine/posix_engine/wakeup_fd_eventfd.cc
+  src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.cc
+  src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.cc
+  src/core/lib/event_engine/resolved_address.cc
+  src/core/lib/event_engine/shim.cc
+  src/core/lib/event_engine/slice.cc
+  src/core/lib/event_engine/slice_buffer.cc
+  src/core/lib/event_engine/tcp_socket_utils.cc
+  src/core/lib/event_engine/thread_pool/thread_count.cc
+  src/core/lib/event_engine/thread_pool/thread_pool_factory.cc
+  src/core/lib/event_engine/thread_pool/work_stealing_thread_pool.cc
+  src/core/lib/event_engine/thready_event_engine/thready_event_engine.cc
+  src/core/lib/event_engine/time_util.cc
+  src/core/lib/event_engine/trace.cc
+  src/core/lib/event_engine/utils.cc
+  src/core/lib/event_engine/windows/grpc_polled_fd_windows.cc
+  src/core/lib/event_engine/windows/iocp.cc
+  src/core/lib/event_engine/windows/native_windows_dns_resolver.cc
+  src/core/lib/event_engine/windows/win_socket.cc
+  src/core/lib/event_engine/windows/windows_endpoint.cc
+  src/core/lib/event_engine/windows/windows_engine.cc
+  src/core/lib/event_engine/windows/windows_listener.cc
+  src/core/lib/event_engine/work_queue/basic_work_queue.cc
+  src/core/lib/experiments/config.cc
+  src/core/lib/experiments/experiments.cc
+  src/core/lib/gprpp/load_file.cc
+  src/core/lib/gprpp/per_cpu.cc
+  src/core/lib/gprpp/ref_counted_string.cc
+  src/core/lib/gprpp/status_helper.cc
+  src/core/lib/gprpp/time.cc
+  src/core/lib/gprpp/time_averaged_stats.cc
+  src/core/lib/gprpp/validation_errors.cc
+  src/core/lib/gprpp/work_serializer.cc
+  src/core/lib/handshaker/proxy_mapper_registry.cc
+  src/core/lib/iomgr/buffer_list.cc
+  src/core/lib/iomgr/call_combiner.cc
+  src/core/lib/iomgr/cfstream_handle.cc
+  src/core/lib/iomgr/closure.cc
+  src/core/lib/iomgr/combiner.cc
+  src/core/lib/iomgr/dualstack_socket_posix.cc
+  src/core/lib/iomgr/endpoint.cc
+  src/core/lib/iomgr/endpoint_cfstream.cc
+  src/core/lib/iomgr/endpoint_pair_posix.cc
+  src/core/lib/iomgr/endpoint_pair_windows.cc
+  src/core/lib/iomgr/error.cc
+  src/core/lib/iomgr/error_cfstream.cc
+  src/core/lib/iomgr/ev_apple.cc
+  src/core/lib/iomgr/ev_epoll1_linux.cc
+  src/core/lib/iomgr/ev_poll_posix.cc
+  src/core/lib/iomgr/ev_posix.cc
+  src/core/lib/iomgr/ev_windows.cc
+  src/core/lib/iomgr/event_engine_shims/closure.cc
+  src/core/lib/iomgr/event_engine_shims/endpoint.cc
+  src/core/lib/iomgr/event_engine_shims/tcp_client.cc
+  src/core/lib/iomgr/exec_ctx.cc
+  src/core/lib/iomgr/executor.cc
+  src/core/lib/iomgr/fork_posix.cc
+  src/core/lib/iomgr/fork_windows.cc
+  src/core/lib/iomgr/gethostname_fallback.cc
+  src/core/lib/iomgr/gethostname_host_name_max.cc
+  src/core/lib/iomgr/gethostname_sysconf.cc
+  src/core/lib/iomgr/grpc_if_nametoindex_posix.cc
+  src/core/lib/iomgr/grpc_if_nametoindex_unsupported.cc
+  src/core/lib/iomgr/internal_errqueue.cc
+  src/core/lib/iomgr/iocp_windows.cc
+  src/core/lib/iomgr/iomgr.cc
+  src/core/lib/iomgr/iomgr_internal.cc
+  src/core/lib/iomgr/iomgr_posix.cc
+  src/core/lib/iomgr/iomgr_posix_cfstream.cc
+  src/core/lib/iomgr/iomgr_windows.cc
+  src/core/lib/iomgr/lockfree_event.cc
+  src/core/lib/iomgr/polling_entity.cc
+  src/core/lib/iomgr/pollset.cc
+  src/core/lib/iomgr/pollset_set.cc
+  src/core/lib/iomgr/pollset_set_windows.cc
+  src/core/lib/iomgr/pollset_windows.cc
+  src/core/lib/iomgr/resolve_address.cc
+  src/core/lib/iomgr/resolve_address_posix.cc
+  src/core/lib/iomgr/resolve_address_windows.cc
+  src/core/lib/iomgr/sockaddr_utils_posix.cc
+  src/core/lib/iomgr/socket_factory_posix.cc
+  src/core/lib/iomgr/socket_mutator.cc
+  src/core/lib/iomgr/socket_utils_common_posix.cc
+  src/core/lib/iomgr/socket_utils_linux.cc
+  src/core/lib/iomgr/socket_utils_posix.cc
+  src/core/lib/iomgr/socket_utils_windows.cc
+  src/core/lib/iomgr/socket_windows.cc
+  src/core/lib/iomgr/systemd_utils.cc
+  src/core/lib/iomgr/tcp_client.cc
+  src/core/lib/iomgr/tcp_client_cfstream.cc
+  src/core/lib/iomgr/tcp_client_posix.cc
+  src/core/lib/iomgr/tcp_client_windows.cc
+  src/core/lib/iomgr/tcp_posix.cc
+  src/core/lib/iomgr/tcp_server.cc
+  src/core/lib/iomgr/tcp_server_posix.cc
+  src/core/lib/iomgr/tcp_server_utils_posix_common.cc
+  src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
+  src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc
+  src/core/lib/iomgr/tcp_server_windows.cc
+  src/core/lib/iomgr/tcp_windows.cc
+  src/core/lib/iomgr/timer.cc
+  src/core/lib/iomgr/timer_generic.cc
+  src/core/lib/iomgr/timer_heap.cc
+  src/core/lib/iomgr/timer_manager.cc
+  src/core/lib/iomgr/unix_sockets_posix.cc
+  src/core/lib/iomgr/unix_sockets_posix_noop.cc
+  src/core/lib/iomgr/vsock.cc
+  src/core/lib/iomgr/wakeup_fd_eventfd.cc
+  src/core/lib/iomgr/wakeup_fd_nospecial.cc
+  src/core/lib/iomgr/wakeup_fd_pipe.cc
+  src/core/lib/iomgr/wakeup_fd_posix.cc
+  src/core/lib/json/json_writer.cc
+  src/core/lib/promise/activity.cc
+  src/core/lib/promise/party.cc
+  src/core/lib/promise/trace.cc
+  src/core/lib/resource_quota/api.cc
+  src/core/lib/resource_quota/arena.cc
+  src/core/lib/resource_quota/connection_quota.cc
+  src/core/lib/resource_quota/memory_quota.cc
+  src/core/lib/resource_quota/periodic_update.cc
+  src/core/lib/resource_quota/resource_quota.cc
+  src/core/lib/resource_quota/thread_quota.cc
+  src/core/lib/resource_quota/trace.cc
+  src/core/lib/security/certificate_provider/certificate_provider_registry.cc
+  src/core/lib/security/credentials/alts/check_gcp_environment.cc
+  src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc
+  src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc
+  src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc
+  src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
+  src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc
+  src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
+  src/core/lib/slice/percent_encoding.cc
+  src/core/lib/slice/slice.cc
+  src/core/lib/slice/slice_buffer.cc
+  src/core/lib/slice/slice_refcount.cc
+  src/core/lib/slice/slice_string_helpers.cc
+  src/core/lib/surface/api_trace.cc
+  src/core/lib/surface/byte_buffer.cc
+  src/core/lib/surface/byte_buffer_reader.cc
+  src/core/lib/surface/call.cc
+  src/core/lib/surface/call_details.cc
+  src/core/lib/surface/call_log_batch.cc
+  src/core/lib/surface/channel.cc
+  src/core/lib/surface/channel_init.cc
+  src/core/lib/surface/channel_stack_type.cc
+  src/core/lib/surface/completion_queue.cc
+  src/core/lib/surface/completion_queue_factory.cc
+  src/core/lib/surface/event_string.cc
+  src/core/lib/surface/init_internally.cc
+  src/core/lib/surface/lame_client.cc
+  src/core/lib/surface/metadata_array.cc
+  src/core/lib/surface/validate_metadata.cc
+  src/core/lib/surface/version.cc
+  src/core/lib/surface/wait_for_cq_end_op.cc
+  src/core/lib/transport/batch_builder.cc
+  src/core/lib/transport/call_arena_allocator.cc
+  src/core/lib/transport/call_filters.cc
+  src/core/lib/transport/call_final_info.cc
+  src/core/lib/transport/call_spine.cc
+  src/core/lib/transport/connectivity_state.cc
+  src/core/lib/transport/error_utils.cc
+  src/core/lib/transport/handshaker_registry.cc
+  src/core/lib/transport/interception_chain.cc
+  src/core/lib/transport/message.cc
+  src/core/lib/transport/metadata.cc
+  src/core/lib/transport/metadata_batch.cc
+  src/core/lib/transport/parsed_metadata.cc
+  src/core/lib/transport/status_conversion.cc
+  src/core/lib/transport/timeout_encoding.cc
+  src/core/lib/transport/transport.cc
+  src/core/lib/transport/transport_op_string.cc
+  src/core/lib/uri/uri_parser.cc
+  src/core/load_balancing/lb_policy.cc
+  src/core/load_balancing/lb_policy_registry.cc
+  src/core/resolver/endpoint_addresses.cc
+  src/core/resolver/resolver.cc
+  src/core/resolver/resolver_registry.cc
+  src/core/service_config/service_config_parser.cc
+  src/core/tsi/alts/handshaker/transport_security_common_api.cc
+  test/core/transport/interception_chain_test.cc
+  third_party/upb/upb/mini_descriptor/build_enum.c
+  third_party/upb/upb/mini_descriptor/decode.c
+  third_party/upb/upb/mini_descriptor/internal/base92.c
+  third_party/upb/upb/mini_descriptor/internal/encode.c
+  third_party/upb/upb/mini_descriptor/link.c
+  third_party/upb/upb/wire/decode.c
+  third_party/upb/upb/wire/encode.c
+  third_party/upb/upb/wire/eps_copy_input_stream.c
+  third_party/upb/upb/wire/internal/decode_fast.c
+  third_party/upb/upb/wire/reader.c
+)
+if(WIN32 AND MSVC)
+  if(BUILD_SHARED_LIBS)
+    target_compile_definitions(interception_chain_test
+    PRIVATE
+      "GPR_DLL_IMPORTS"
+    )
+  endif()
+endif()
+target_compile_features(interception_chain_test PUBLIC cxx_std_14)
+target_include_directories(interception_chain_test
+  PRIVATE
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/include
+    ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
+    ${_gRPC_RE2_INCLUDE_DIR}
+    ${_gRPC_SSL_INCLUDE_DIR}
+    ${_gRPC_UPB_GENERATED_DIR}
+    ${_gRPC_UPB_GRPC_GENERATED_DIR}
+    ${_gRPC_UPB_INCLUDE_DIR}
+    ${_gRPC_XXHASH_INCLUDE_DIR}
+    ${_gRPC_ZLIB_INCLUDE_DIR}
+    third_party/googletest/googletest/include
+    third_party/googletest/googletest
+    third_party/googletest/googlemock/include
+    third_party/googletest/googlemock
+    ${_gRPC_PROTO_GENS_DIR}
+)
+
+target_link_libraries(interception_chain_test
+  ${_gRPC_ALLTARGETS_LIBRARIES}
+  gtest
+  utf8_range_lib
+  upb_message_lib
+  ${_gRPC_ZLIB_LIBRARIES}
+  absl::config
+  absl::no_destructor
+  absl::cleanup
+  absl::flat_hash_map
+  absl::inlined_vector
+  absl::function_ref
+  absl::hash
+  absl::type_traits
+  absl::statusor
+  absl::span
+  absl::utility
+  ${_gRPC_CARES_LIBRARIES}
+  gpr
+  ${_gRPC_ADDRESS_SORTING_LIBRARIES}
+)
+
+
 endif()
 if(gRPC_BUILD_TESTS)
 
diff --git a/Makefile b/Makefile
index 33f21133e1f..9d3d160f518 100644
--- a/Makefile
+++ b/Makefile
@@ -1406,9 +1406,9 @@ LIBGRPC_SRC = \
     src/core/lib/surface/wait_for_cq_end_op.cc \
     src/core/lib/transport/batch_builder.cc \
     src/core/lib/transport/bdp_estimator.cc \
+    src/core/lib/transport/call_arena_allocator.cc \
     src/core/lib/transport/call_filters.cc \
     src/core/lib/transport/call_final_info.cc \
-    src/core/lib/transport/call_size_estimator.cc \
     src/core/lib/transport/call_spine.cc \
     src/core/lib/transport/connectivity_state.cc \
     src/core/lib/transport/endpoint_info_handshaker.cc \
diff --git a/Package.swift b/Package.swift
index 0eb0d795a66..7fab159ad58 100644
--- a/Package.swift
+++ b/Package.swift
@@ -1803,12 +1803,12 @@ let package = Package(
         "src/core/lib/transport/batch_builder.h",
         "src/core/lib/transport/bdp_estimator.cc",
         "src/core/lib/transport/bdp_estimator.h",
+        "src/core/lib/transport/call_arena_allocator.cc",
+        "src/core/lib/transport/call_arena_allocator.h",
         "src/core/lib/transport/call_filters.cc",
         "src/core/lib/transport/call_filters.h",
         "src/core/lib/transport/call_final_info.cc",
         "src/core/lib/transport/call_final_info.h",
-        "src/core/lib/transport/call_size_estimator.cc",
-        "src/core/lib/transport/call_size_estimator.h",
         "src/core/lib/transport/call_spine.cc",
         "src/core/lib/transport/call_spine.h",
         "src/core/lib/transport/connectivity_state.cc",
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index 8af816d7535..ca6c1d501a7 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -1138,9 +1138,9 @@ libs:
   - src/core/lib/surface/wait_for_cq_end_op.h
   - src/core/lib/transport/batch_builder.h
   - src/core/lib/transport/bdp_estimator.h
+  - src/core/lib/transport/call_arena_allocator.h
   - src/core/lib/transport/call_filters.h
   - src/core/lib/transport/call_final_info.h
-  - src/core/lib/transport/call_size_estimator.h
   - src/core/lib/transport/call_spine.h
   - src/core/lib/transport/connectivity_state.h
   - src/core/lib/transport/custom_metadata.h
@@ -1939,9 +1939,9 @@ libs:
   - src/core/lib/surface/wait_for_cq_end_op.cc
   - src/core/lib/transport/batch_builder.cc
   - src/core/lib/transport/bdp_estimator.cc
+  - src/core/lib/transport/call_arena_allocator.cc
   - src/core/lib/transport/call_filters.cc
   - src/core/lib/transport/call_final_info.cc
-  - src/core/lib/transport/call_size_estimator.cc
   - src/core/lib/transport/call_spine.cc
   - src/core/lib/transport/connectivity_state.cc
   - src/core/lib/transport/endpoint_info_handshaker.cc
@@ -2605,9 +2605,9 @@ libs:
   - src/core/lib/surface/wait_for_cq_end_op.h
   - src/core/lib/transport/batch_builder.h
   - src/core/lib/transport/bdp_estimator.h
+  - src/core/lib/transport/call_arena_allocator.h
   - src/core/lib/transport/call_filters.h
   - src/core/lib/transport/call_final_info.h
-  - src/core/lib/transport/call_size_estimator.h
   - src/core/lib/transport/call_spine.h
   - src/core/lib/transport/connectivity_state.h
   - src/core/lib/transport/custom_metadata.h
@@ -3024,9 +3024,9 @@ libs:
   - src/core/lib/surface/wait_for_cq_end_op.cc
   - src/core/lib/transport/batch_builder.cc
   - src/core/lib/transport/bdp_estimator.cc
+  - src/core/lib/transport/call_arena_allocator.cc
   - src/core/lib/transport/call_filters.cc
   - src/core/lib/transport/call_final_info.cc
-  - src/core/lib/transport/call_size_estimator.cc
   - src/core/lib/transport/call_spine.cc
   - src/core/lib/transport/connectivity_state.cc
   - src/core/lib/transport/endpoint_info_handshaker.cc
@@ -4616,7 +4616,6 @@ libs:
   - src/core/lib/promise/party.h
   - src/core/lib/promise/pipe.h
   - src/core/lib/promise/poll.h
-  - src/core/lib/promise/prioritized_race.h
   - src/core/lib/promise/promise.h
   - src/core/lib/promise/race.h
   - src/core/lib/promise/seq.h
@@ -4684,6 +4683,7 @@ libs:
   - src/core/lib/surface/validate_metadata.h
   - src/core/lib/surface/wait_for_cq_end_op.h
   - src/core/lib/transport/batch_builder.h
+  - src/core/lib/transport/call_arena_allocator.h
   - src/core/lib/transport/call_filters.h
   - src/core/lib/transport/call_final_info.h
   - src/core/lib/transport/call_spine.h
@@ -4981,6 +4981,7 @@ libs:
   - src/core/lib/surface/version.cc
   - src/core/lib/surface/wait_for_cq_end_op.cc
   - src/core/lib/transport/batch_builder.cc
+  - src/core/lib/transport/call_arena_allocator.cc
   - src/core/lib/transport/call_filters.cc
   - src/core/lib/transport/call_final_info.cc
   - src/core/lib/transport/call_spine.cc
@@ -6454,6 +6455,7 @@ targets:
   - src/core/lib/transport/simple_slice_based_metadata.h
   - src/core/lib/transport/status_conversion.h
   - src/core/lib/transport/timeout_encoding.h
+  - test/core/promise/poll_matcher.h
   - third_party/upb/upb/generated_code_support.h
   - third_party/upb/upb/mini_descriptor/build_enum.h
   - third_party/upb/upb/mini_descriptor/decode.h
@@ -11649,6 +11651,599 @@ targets:
   - absl/status:statusor
   - gpr
   uses_polling: false
+- name: interception_chain_test
+  gtest: true
+  build: test
+  language: c++
+  headers:
+  - src/core/channelz/channel_trace.h
+  - src/core/channelz/channelz.h
+  - src/core/channelz/channelz_registry.h
+  - src/core/ext/upb-gen/google/protobuf/any.upb.h
+  - src/core/ext/upb-gen/google/protobuf/any.upb_minitable.h
+  - src/core/ext/upb-gen/google/rpc/status.upb.h
+  - src/core/ext/upb-gen/google/rpc/status.upb_minitable.h
+  - src/core/ext/upb-gen/src/proto/grpc/gcp/altscontext.upb.h
+  - src/core/ext/upb-gen/src/proto/grpc/gcp/altscontext.upb_minitable.h
+  - src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb.h
+  - src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb_minitable.h
+  - src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb.h
+  - src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb_minitable.h
+  - src/core/lib/address_utils/parse_address.h
+  - src/core/lib/address_utils/sockaddr_utils.h
+  - src/core/lib/avl/avl.h
+  - src/core/lib/backoff/backoff.h
+  - src/core/lib/channel/call_finalization.h
+  - src/core/lib/channel/call_tracer.h
+  - src/core/lib/channel/channel_args.h
+  - src/core/lib/channel/channel_args_preconditioning.h
+  - src/core/lib/channel/channel_fwd.h
+  - src/core/lib/channel/channel_stack.h
+  - src/core/lib/channel/channel_stack_builder.h
+  - src/core/lib/channel/channel_stack_builder_impl.h
+  - src/core/lib/channel/channel_stack_trace.h
+  - src/core/lib/channel/connected_channel.h
+  - src/core/lib/channel/context.h
+  - src/core/lib/channel/metrics.h
+  - src/core/lib/channel/promise_based_filter.h
+  - src/core/lib/channel/status_util.h
+  - src/core/lib/channel/tcp_tracer.h
+  - src/core/lib/compression/compression_internal.h
+  - src/core/lib/compression/message_compress.h
+  - src/core/lib/config/core_configuration.h
+  - src/core/lib/debug/event_log.h
+  - src/core/lib/debug/histogram_view.h
+  - src/core/lib/debug/stats.h
+  - src/core/lib/debug/stats_data.h
+  - src/core/lib/debug/trace.h
+  - src/core/lib/event_engine/ares_resolver.h
+  - src/core/lib/event_engine/cf_engine/cf_engine.h
+  - src/core/lib/event_engine/cf_engine/cfstream_endpoint.h
+  - src/core/lib/event_engine/cf_engine/cftype_unique_ref.h
+  - src/core/lib/event_engine/cf_engine/dns_service_resolver.h
+  - src/core/lib/event_engine/channel_args_endpoint_config.h
+  - src/core/lib/event_engine/common_closures.h
+  - src/core/lib/event_engine/default_event_engine.h
+  - src/core/lib/event_engine/default_event_engine_factory.h
+  - src/core/lib/event_engine/event_engine_context.h
+  - src/core/lib/event_engine/extensions/can_track_errors.h
+  - src/core/lib/event_engine/extensions/chaotic_good_extension.h
+  - src/core/lib/event_engine/extensions/supports_fd.h
+  - src/core/lib/event_engine/forkable.h
+  - src/core/lib/event_engine/grpc_polled_fd.h
+  - src/core/lib/event_engine/handle_containers.h
+  - src/core/lib/event_engine/memory_allocator_factory.h
+  - src/core/lib/event_engine/nameser.h
+  - src/core/lib/event_engine/poller.h
+  - src/core/lib/event_engine/posix.h
+  - src/core/lib/event_engine/posix_engine/ev_epoll1_linux.h
+  - src/core/lib/event_engine/posix_engine/ev_poll_posix.h
+  - src/core/lib/event_engine/posix_engine/event_poller.h
+  - src/core/lib/event_engine/posix_engine/event_poller_posix_default.h
+  - src/core/lib/event_engine/posix_engine/grpc_polled_fd_posix.h
+  - src/core/lib/event_engine/posix_engine/internal_errqueue.h
+  - src/core/lib/event_engine/posix_engine/lockfree_event.h
+  - src/core/lib/event_engine/posix_engine/native_posix_dns_resolver.h
+  - src/core/lib/event_engine/posix_engine/posix_endpoint.h
+  - src/core/lib/event_engine/posix_engine/posix_engine.h
+  - src/core/lib/event_engine/posix_engine/posix_engine_closure.h
+  - src/core/lib/event_engine/posix_engine/posix_engine_listener.h
+  - src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.h
+  - src/core/lib/event_engine/posix_engine/tcp_socket_utils.h
+  - src/core/lib/event_engine/posix_engine/timer.h
+  - src/core/lib/event_engine/posix_engine/timer_heap.h
+  - src/core/lib/event_engine/posix_engine/timer_manager.h
+  - src/core/lib/event_engine/posix_engine/traced_buffer_list.h
+  - src/core/lib/event_engine/posix_engine/wakeup_fd_eventfd.h
+  - src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.h
+  - src/core/lib/event_engine/posix_engine/wakeup_fd_posix.h
+  - src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.h
+  - src/core/lib/event_engine/query_extensions.h
+  - src/core/lib/event_engine/ref_counted_dns_resolver_interface.h
+  - src/core/lib/event_engine/resolved_address_internal.h
+  - src/core/lib/event_engine/shim.h
+  - src/core/lib/event_engine/tcp_socket_utils.h
+  - src/core/lib/event_engine/thread_pool/thread_count.h
+  - src/core/lib/event_engine/thread_pool/thread_pool.h
+  - src/core/lib/event_engine/thread_pool/work_stealing_thread_pool.h
+  - src/core/lib/event_engine/thready_event_engine/thready_event_engine.h
+  - src/core/lib/event_engine/time_util.h
+  - src/core/lib/event_engine/trace.h
+  - src/core/lib/event_engine/utils.h
+  - src/core/lib/event_engine/windows/grpc_polled_fd_windows.h
+  - src/core/lib/event_engine/windows/iocp.h
+  - src/core/lib/event_engine/windows/native_windows_dns_resolver.h
+  - src/core/lib/event_engine/windows/win_socket.h
+  - src/core/lib/event_engine/windows/windows_endpoint.h
+  - src/core/lib/event_engine/windows/windows_engine.h
+  - src/core/lib/event_engine/windows/windows_listener.h
+  - src/core/lib/event_engine/work_queue/basic_work_queue.h
+  - src/core/lib/event_engine/work_queue/work_queue.h
+  - src/core/lib/experiments/config.h
+  - src/core/lib/experiments/experiments.h
+  - src/core/lib/gpr/spinlock.h
+  - src/core/lib/gprpp/atomic_utils.h
+  - src/core/lib/gprpp/bitset.h
+  - src/core/lib/gprpp/chunked_vector.h
+  - src/core/lib/gprpp/cpp_impl_of.h
+  - src/core/lib/gprpp/down_cast.h
+  - src/core/lib/gprpp/dual_ref_counted.h
+  - src/core/lib/gprpp/if_list.h
+  - src/core/lib/gprpp/load_file.h
+  - src/core/lib/gprpp/manual_constructor.h
+  - src/core/lib/gprpp/match.h
+  - src/core/lib/gprpp/notification.h
+  - src/core/lib/gprpp/orphanable.h
+  - src/core/lib/gprpp/overload.h
+  - src/core/lib/gprpp/packed_table.h
+  - src/core/lib/gprpp/per_cpu.h
+  - src/core/lib/gprpp/ref_counted.h
+  - src/core/lib/gprpp/ref_counted_ptr.h
+  - src/core/lib/gprpp/ref_counted_string.h
+  - src/core/lib/gprpp/sorted_pack.h
+  - src/core/lib/gprpp/status_helper.h
+  - src/core/lib/gprpp/table.h
+  - src/core/lib/gprpp/time.h
+  - src/core/lib/gprpp/time_averaged_stats.h
+  - src/core/lib/gprpp/type_list.h
+  - src/core/lib/gprpp/unique_type_name.h
+  - src/core/lib/gprpp/validation_errors.h
+  - src/core/lib/gprpp/work_serializer.h
+  - src/core/lib/handshaker/proxy_mapper.h
+  - src/core/lib/handshaker/proxy_mapper_registry.h
+  - src/core/lib/iomgr/block_annotate.h
+  - src/core/lib/iomgr/buffer_list.h
+  - src/core/lib/iomgr/call_combiner.h
+  - src/core/lib/iomgr/cfstream_handle.h
+  - src/core/lib/iomgr/closure.h
+  - src/core/lib/iomgr/combiner.h
+  - src/core/lib/iomgr/dynamic_annotations.h
+  - src/core/lib/iomgr/endpoint.h
+  - src/core/lib/iomgr/endpoint_cfstream.h
+  - src/core/lib/iomgr/endpoint_pair.h
+  - src/core/lib/iomgr/error.h
+  - src/core/lib/iomgr/error_cfstream.h
+  - src/core/lib/iomgr/ev_apple.h
+  - src/core/lib/iomgr/ev_epoll1_linux.h
+  - src/core/lib/iomgr/ev_poll_posix.h
+  - src/core/lib/iomgr/ev_posix.h
+  - src/core/lib/iomgr/event_engine_shims/closure.h
+  - src/core/lib/iomgr/event_engine_shims/endpoint.h
+  - src/core/lib/iomgr/event_engine_shims/tcp_client.h
+  - src/core/lib/iomgr/exec_ctx.h
+  - src/core/lib/iomgr/executor.h
+  - src/core/lib/iomgr/gethostname.h
+  - src/core/lib/iomgr/grpc_if_nametoindex.h
+  - src/core/lib/iomgr/internal_errqueue.h
+  - src/core/lib/iomgr/iocp_windows.h
+  - src/core/lib/iomgr/iomgr.h
+  - src/core/lib/iomgr/iomgr_fwd.h
+  - src/core/lib/iomgr/iomgr_internal.h
+  - src/core/lib/iomgr/lockfree_event.h
+  - src/core/lib/iomgr/nameser.h
+  - src/core/lib/iomgr/polling_entity.h
+  - src/core/lib/iomgr/pollset.h
+  - src/core/lib/iomgr/pollset_set.h
+  - src/core/lib/iomgr/pollset_set_windows.h
+  - src/core/lib/iomgr/pollset_windows.h
+  - src/core/lib/iomgr/port.h
+  - src/core/lib/iomgr/python_util.h
+  - src/core/lib/iomgr/resolve_address.h
+  - src/core/lib/iomgr/resolve_address_impl.h
+  - src/core/lib/iomgr/resolve_address_posix.h
+  - src/core/lib/iomgr/resolve_address_windows.h
+  - src/core/lib/iomgr/resolved_address.h
+  - src/core/lib/iomgr/sockaddr.h
+  - src/core/lib/iomgr/sockaddr_posix.h
+  - src/core/lib/iomgr/sockaddr_windows.h
+  - src/core/lib/iomgr/socket_factory_posix.h
+  - src/core/lib/iomgr/socket_mutator.h
+  - src/core/lib/iomgr/socket_utils.h
+  - src/core/lib/iomgr/socket_utils_posix.h
+  - src/core/lib/iomgr/socket_windows.h
+  - src/core/lib/iomgr/systemd_utils.h
+  - src/core/lib/iomgr/tcp_client.h
+  - src/core/lib/iomgr/tcp_client_posix.h
+  - src/core/lib/iomgr/tcp_posix.h
+  - src/core/lib/iomgr/tcp_server.h
+  - src/core/lib/iomgr/tcp_server_utils_posix.h
+  - src/core/lib/iomgr/tcp_windows.h
+  - src/core/lib/iomgr/timer.h
+  - src/core/lib/iomgr/timer_generic.h
+  - src/core/lib/iomgr/timer_heap.h
+  - src/core/lib/iomgr/timer_manager.h
+  - src/core/lib/iomgr/unix_sockets_posix.h
+  - src/core/lib/iomgr/vsock.h
+  - src/core/lib/iomgr/wakeup_fd_pipe.h
+  - src/core/lib/iomgr/wakeup_fd_posix.h
+  - src/core/lib/json/json.h
+  - src/core/lib/json/json_args.h
+  - src/core/lib/json/json_writer.h
+  - src/core/lib/promise/activity.h
+  - src/core/lib/promise/all_ok.h
+  - src/core/lib/promise/arena_promise.h
+  - src/core/lib/promise/context.h
+  - src/core/lib/promise/detail/basic_seq.h
+  - src/core/lib/promise/detail/join_state.h
+  - src/core/lib/promise/detail/promise_factory.h
+  - src/core/lib/promise/detail/promise_like.h
+  - src/core/lib/promise/detail/seq_state.h
+  - src/core/lib/promise/detail/status.h
+  - src/core/lib/promise/exec_ctx_wakeup_scheduler.h
+  - src/core/lib/promise/for_each.h
+  - src/core/lib/promise/if.h
+  - src/core/lib/promise/interceptor_list.h
+  - src/core/lib/promise/latch.h
+  - src/core/lib/promise/loop.h
+  - src/core/lib/promise/map.h
+  - src/core/lib/promise/party.h
+  - src/core/lib/promise/pipe.h
+  - src/core/lib/promise/poll.h
+  - src/core/lib/promise/promise.h
+  - src/core/lib/promise/race.h
+  - src/core/lib/promise/seq.h
+  - src/core/lib/promise/status_flag.h
+  - src/core/lib/promise/trace.h
+  - src/core/lib/promise/try_seq.h
+  - src/core/lib/resource_quota/api.h
+  - src/core/lib/resource_quota/arena.h
+  - src/core/lib/resource_quota/connection_quota.h
+  - src/core/lib/resource_quota/memory_quota.h
+  - src/core/lib/resource_quota/periodic_update.h
+  - src/core/lib/resource_quota/resource_quota.h
+  - src/core/lib/resource_quota/thread_quota.h
+  - src/core/lib/resource_quota/trace.h
+  - src/core/lib/security/certificate_provider/certificate_provider_factory.h
+  - src/core/lib/security/certificate_provider/certificate_provider_registry.h
+  - src/core/lib/security/credentials/alts/check_gcp_environment.h
+  - src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h
+  - src/core/lib/security/credentials/channel_creds_registry.h
+  - src/core/lib/slice/percent_encoding.h
+  - src/core/lib/slice/slice.h
+  - src/core/lib/slice/slice_buffer.h
+  - src/core/lib/slice/slice_internal.h
+  - src/core/lib/slice/slice_refcount.h
+  - src/core/lib/slice/slice_string_helpers.h
+  - src/core/lib/surface/api_trace.h
+  - src/core/lib/surface/call.h
+  - src/core/lib/surface/call_test_only.h
+  - src/core/lib/surface/call_trace.h
+  - src/core/lib/surface/channel.h
+  - src/core/lib/surface/channel_init.h
+  - src/core/lib/surface/channel_stack_type.h
+  - src/core/lib/surface/completion_queue.h
+  - src/core/lib/surface/completion_queue_factory.h
+  - src/core/lib/surface/event_string.h
+  - src/core/lib/surface/init.h
+  - src/core/lib/surface/init_internally.h
+  - src/core/lib/surface/lame_client.h
+  - src/core/lib/surface/server_interface.h
+  - src/core/lib/surface/validate_metadata.h
+  - src/core/lib/surface/wait_for_cq_end_op.h
+  - src/core/lib/transport/batch_builder.h
+  - src/core/lib/transport/call_arena_allocator.h
+  - src/core/lib/transport/call_destination.h
+  - src/core/lib/transport/call_filters.h
+  - src/core/lib/transport/call_final_info.h
+  - src/core/lib/transport/call_spine.h
+  - src/core/lib/transport/connectivity_state.h
+  - src/core/lib/transport/custom_metadata.h
+  - src/core/lib/transport/error_utils.h
+  - src/core/lib/transport/handshaker_factory.h
+  - src/core/lib/transport/handshaker_registry.h
+  - src/core/lib/transport/http2_errors.h
+  - src/core/lib/transport/interception_chain.h
+  - src/core/lib/transport/message.h
+  - src/core/lib/transport/metadata.h
+  - src/core/lib/transport/metadata_batch.h
+  - src/core/lib/transport/metadata_compression_traits.h
+  - src/core/lib/transport/parsed_metadata.h
+  - src/core/lib/transport/simple_slice_based_metadata.h
+  - src/core/lib/transport/status_conversion.h
+  - src/core/lib/transport/timeout_encoding.h
+  - src/core/lib/transport/transport.h
+  - src/core/lib/transport/transport_fwd.h
+  - src/core/lib/uri/uri_parser.h
+  - src/core/load_balancing/backend_metric_data.h
+  - src/core/load_balancing/lb_policy.h
+  - src/core/load_balancing/lb_policy_factory.h
+  - src/core/load_balancing/lb_policy_registry.h
+  - src/core/load_balancing/subchannel_interface.h
+  - src/core/resolver/endpoint_addresses.h
+  - src/core/resolver/resolver.h
+  - src/core/resolver/resolver_factory.h
+  - src/core/resolver/resolver_registry.h
+  - src/core/resolver/server_address.h
+  - src/core/service_config/service_config.h
+  - src/core/service_config/service_config_call_data.h
+  - src/core/service_config/service_config_parser.h
+  - src/core/tsi/alts/handshaker/transport_security_common_api.h
+  - test/core/promise/poll_matcher.h
+  - third_party/upb/upb/generated_code_support.h
+  - third_party/upb/upb/mini_descriptor/build_enum.h
+  - third_party/upb/upb/mini_descriptor/decode.h
+  - third_party/upb/upb/mini_descriptor/internal/base92.h
+  - third_party/upb/upb/mini_descriptor/internal/decoder.h
+  - third_party/upb/upb/mini_descriptor/internal/encode.h
+  - third_party/upb/upb/mini_descriptor/internal/encode.hpp
+  - third_party/upb/upb/mini_descriptor/internal/modifiers.h
+  - third_party/upb/upb/mini_descriptor/internal/wire_constants.h
+  - third_party/upb/upb/mini_descriptor/link.h
+  - third_party/upb/upb/wire/decode.h
+  - third_party/upb/upb/wire/encode.h
+  - third_party/upb/upb/wire/eps_copy_input_stream.h
+  - third_party/upb/upb/wire/internal/constants.h
+  - third_party/upb/upb/wire/internal/decode_fast.h
+  - third_party/upb/upb/wire/internal/decoder.h
+  - third_party/upb/upb/wire/internal/reader.h
+  - third_party/upb/upb/wire/reader.h
+  - third_party/upb/upb/wire/types.h
+  src:
+  - src/core/channelz/channel_trace.cc
+  - src/core/channelz/channelz.cc
+  - src/core/channelz/channelz_registry.cc
+  - src/core/ext/upb-gen/google/protobuf/any.upb_minitable.c
+  - src/core/ext/upb-gen/google/rpc/status.upb_minitable.c
+  - src/core/ext/upb-gen/src/proto/grpc/gcp/altscontext.upb_minitable.c
+  - src/core/ext/upb-gen/src/proto/grpc/gcp/handshaker.upb_minitable.c
+  - src/core/ext/upb-gen/src/proto/grpc/gcp/transport_security_common.upb_minitable.c
+  - src/core/lib/address_utils/parse_address.cc
+  - src/core/lib/address_utils/sockaddr_utils.cc
+  - src/core/lib/backoff/backoff.cc
+  - src/core/lib/channel/call_tracer.cc
+  - src/core/lib/channel/channel_args.cc
+  - src/core/lib/channel/channel_args_preconditioning.cc
+  - src/core/lib/channel/channel_stack.cc
+  - src/core/lib/channel/channel_stack_builder.cc
+  - src/core/lib/channel/channel_stack_builder_impl.cc
+  - src/core/lib/channel/channel_stack_trace.cc
+  - src/core/lib/channel/connected_channel.cc
+  - src/core/lib/channel/metrics.cc
+  - src/core/lib/channel/promise_based_filter.cc
+  - src/core/lib/channel/status_util.cc
+  - src/core/lib/compression/compression.cc
+  - src/core/lib/compression/compression_internal.cc
+  - src/core/lib/compression/message_compress.cc
+  - src/core/lib/config/core_configuration.cc
+  - src/core/lib/debug/event_log.cc
+  - src/core/lib/debug/histogram_view.cc
+  - src/core/lib/debug/stats.cc
+  - src/core/lib/debug/stats_data.cc
+  - src/core/lib/debug/trace.cc
+  - src/core/lib/event_engine/ares_resolver.cc
+  - src/core/lib/event_engine/cf_engine/cf_engine.cc
+  - src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc
+  - src/core/lib/event_engine/cf_engine/dns_service_resolver.cc
+  - src/core/lib/event_engine/channel_args_endpoint_config.cc
+  - src/core/lib/event_engine/default_event_engine.cc
+  - src/core/lib/event_engine/default_event_engine_factory.cc
+  - src/core/lib/event_engine/event_engine.cc
+  - src/core/lib/event_engine/forkable.cc
+  - src/core/lib/event_engine/posix_engine/ev_epoll1_linux.cc
+  - src/core/lib/event_engine/posix_engine/ev_poll_posix.cc
+  - src/core/lib/event_engine/posix_engine/event_poller_posix_default.cc
+  - src/core/lib/event_engine/posix_engine/internal_errqueue.cc
+  - src/core/lib/event_engine/posix_engine/lockfree_event.cc
+  - src/core/lib/event_engine/posix_engine/native_posix_dns_resolver.cc
+  - src/core/lib/event_engine/posix_engine/posix_endpoint.cc
+  - src/core/lib/event_engine/posix_engine/posix_engine.cc
+  - src/core/lib/event_engine/posix_engine/posix_engine_listener.cc
+  - src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.cc
+  - src/core/lib/event_engine/posix_engine/tcp_socket_utils.cc
+  - src/core/lib/event_engine/posix_engine/timer.cc
+  - src/core/lib/event_engine/posix_engine/timer_heap.cc
+  - src/core/lib/event_engine/posix_engine/timer_manager.cc
+  - src/core/lib/event_engine/posix_engine/traced_buffer_list.cc
+  - src/core/lib/event_engine/posix_engine/wakeup_fd_eventfd.cc
+  - src/core/lib/event_engine/posix_engine/wakeup_fd_pipe.cc
+  - src/core/lib/event_engine/posix_engine/wakeup_fd_posix_default.cc
+  - src/core/lib/event_engine/resolved_address.cc
+  - src/core/lib/event_engine/shim.cc
+  - src/core/lib/event_engine/slice.cc
+  - src/core/lib/event_engine/slice_buffer.cc
+  - src/core/lib/event_engine/tcp_socket_utils.cc
+  - src/core/lib/event_engine/thread_pool/thread_count.cc
+  - src/core/lib/event_engine/thread_pool/thread_pool_factory.cc
+  - src/core/lib/event_engine/thread_pool/work_stealing_thread_pool.cc
+  - src/core/lib/event_engine/thready_event_engine/thready_event_engine.cc
+  - src/core/lib/event_engine/time_util.cc
+  - src/core/lib/event_engine/trace.cc
+  - src/core/lib/event_engine/utils.cc
+  - src/core/lib/event_engine/windows/grpc_polled_fd_windows.cc
+  - src/core/lib/event_engine/windows/iocp.cc
+  - src/core/lib/event_engine/windows/native_windows_dns_resolver.cc
+  - src/core/lib/event_engine/windows/win_socket.cc
+  - src/core/lib/event_engine/windows/windows_endpoint.cc
+  - src/core/lib/event_engine/windows/windows_engine.cc
+  - src/core/lib/event_engine/windows/windows_listener.cc
+  - src/core/lib/event_engine/work_queue/basic_work_queue.cc
+  - src/core/lib/experiments/config.cc
+  - src/core/lib/experiments/experiments.cc
+  - src/core/lib/gprpp/load_file.cc
+  - src/core/lib/gprpp/per_cpu.cc
+  - src/core/lib/gprpp/ref_counted_string.cc
+  - src/core/lib/gprpp/status_helper.cc
+  - src/core/lib/gprpp/time.cc
+  - src/core/lib/gprpp/time_averaged_stats.cc
+  - src/core/lib/gprpp/validation_errors.cc
+  - src/core/lib/gprpp/work_serializer.cc
+  - src/core/lib/handshaker/proxy_mapper_registry.cc
+  - src/core/lib/iomgr/buffer_list.cc
+  - src/core/lib/iomgr/call_combiner.cc
+  - src/core/lib/iomgr/cfstream_handle.cc
+  - src/core/lib/iomgr/closure.cc
+  - src/core/lib/iomgr/combiner.cc
+  - src/core/lib/iomgr/dualstack_socket_posix.cc
+  - src/core/lib/iomgr/endpoint.cc
+  - src/core/lib/iomgr/endpoint_cfstream.cc
+  - src/core/lib/iomgr/endpoint_pair_posix.cc
+  - src/core/lib/iomgr/endpoint_pair_windows.cc
+  - src/core/lib/iomgr/error.cc
+  - src/core/lib/iomgr/error_cfstream.cc
+  - src/core/lib/iomgr/ev_apple.cc
+  - src/core/lib/iomgr/ev_epoll1_linux.cc
+  - src/core/lib/iomgr/ev_poll_posix.cc
+  - src/core/lib/iomgr/ev_posix.cc
+  - src/core/lib/iomgr/ev_windows.cc
+  - src/core/lib/iomgr/event_engine_shims/closure.cc
+  - src/core/lib/iomgr/event_engine_shims/endpoint.cc
+  - src/core/lib/iomgr/event_engine_shims/tcp_client.cc
+  - src/core/lib/iomgr/exec_ctx.cc
+  - src/core/lib/iomgr/executor.cc
+  - src/core/lib/iomgr/fork_posix.cc
+  - src/core/lib/iomgr/fork_windows.cc
+  - src/core/lib/iomgr/gethostname_fallback.cc
+  - src/core/lib/iomgr/gethostname_host_name_max.cc
+  - src/core/lib/iomgr/gethostname_sysconf.cc
+  - src/core/lib/iomgr/grpc_if_nametoindex_posix.cc
+  - src/core/lib/iomgr/grpc_if_nametoindex_unsupported.cc
+  - src/core/lib/iomgr/internal_errqueue.cc
+  - src/core/lib/iomgr/iocp_windows.cc
+  - src/core/lib/iomgr/iomgr.cc
+  - src/core/lib/iomgr/iomgr_internal.cc
+  - src/core/lib/iomgr/iomgr_posix.cc
+  - src/core/lib/iomgr/iomgr_posix_cfstream.cc
+  - src/core/lib/iomgr/iomgr_windows.cc
+  - src/core/lib/iomgr/lockfree_event.cc
+  - src/core/lib/iomgr/polling_entity.cc
+  - src/core/lib/iomgr/pollset.cc
+  - src/core/lib/iomgr/pollset_set.cc
+  - src/core/lib/iomgr/pollset_set_windows.cc
+  - src/core/lib/iomgr/pollset_windows.cc
+  - src/core/lib/iomgr/resolve_address.cc
+  - src/core/lib/iomgr/resolve_address_posix.cc
+  - src/core/lib/iomgr/resolve_address_windows.cc
+  - src/core/lib/iomgr/sockaddr_utils_posix.cc
+  - src/core/lib/iomgr/socket_factory_posix.cc
+  - src/core/lib/iomgr/socket_mutator.cc
+  - src/core/lib/iomgr/socket_utils_common_posix.cc
+  - src/core/lib/iomgr/socket_utils_linux.cc
+  - src/core/lib/iomgr/socket_utils_posix.cc
+  - src/core/lib/iomgr/socket_utils_windows.cc
+  - src/core/lib/iomgr/socket_windows.cc
+  - src/core/lib/iomgr/systemd_utils.cc
+  - src/core/lib/iomgr/tcp_client.cc
+  - src/core/lib/iomgr/tcp_client_cfstream.cc
+  - src/core/lib/iomgr/tcp_client_posix.cc
+  - src/core/lib/iomgr/tcp_client_windows.cc
+  - src/core/lib/iomgr/tcp_posix.cc
+  - src/core/lib/iomgr/tcp_server.cc
+  - src/core/lib/iomgr/tcp_server_posix.cc
+  - src/core/lib/iomgr/tcp_server_utils_posix_common.cc
+  - src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc
+  - src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc
+  - src/core/lib/iomgr/tcp_server_windows.cc
+  - src/core/lib/iomgr/tcp_windows.cc
+  - src/core/lib/iomgr/timer.cc
+  - src/core/lib/iomgr/timer_generic.cc
+  - src/core/lib/iomgr/timer_heap.cc
+  - src/core/lib/iomgr/timer_manager.cc
+  - src/core/lib/iomgr/unix_sockets_posix.cc
+  - src/core/lib/iomgr/unix_sockets_posix_noop.cc
+  - src/core/lib/iomgr/vsock.cc
+  - src/core/lib/iomgr/wakeup_fd_eventfd.cc
+  - src/core/lib/iomgr/wakeup_fd_nospecial.cc
+  - src/core/lib/iomgr/wakeup_fd_pipe.cc
+  - src/core/lib/iomgr/wakeup_fd_posix.cc
+  - src/core/lib/json/json_writer.cc
+  - src/core/lib/promise/activity.cc
+  - src/core/lib/promise/party.cc
+  - src/core/lib/promise/trace.cc
+  - src/core/lib/resource_quota/api.cc
+  - src/core/lib/resource_quota/arena.cc
+  - src/core/lib/resource_quota/connection_quota.cc
+  - src/core/lib/resource_quota/memory_quota.cc
+  - src/core/lib/resource_quota/periodic_update.cc
+  - src/core/lib/resource_quota/resource_quota.cc
+  - src/core/lib/resource_quota/thread_quota.cc
+  - src/core/lib/resource_quota/trace.cc
+  - src/core/lib/security/certificate_provider/certificate_provider_registry.cc
+  - src/core/lib/security/credentials/alts/check_gcp_environment.cc
+  - src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc
+  - src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc
+  - src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc
+  - src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
+  - src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc
+  - src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
+  - src/core/lib/slice/percent_encoding.cc
+  - src/core/lib/slice/slice.cc
+  - src/core/lib/slice/slice_buffer.cc
+  - src/core/lib/slice/slice_refcount.cc
+  - src/core/lib/slice/slice_string_helpers.cc
+  - src/core/lib/surface/api_trace.cc
+  - src/core/lib/surface/byte_buffer.cc
+  - src/core/lib/surface/byte_buffer_reader.cc
+  - src/core/lib/surface/call.cc
+  - src/core/lib/surface/call_details.cc
+  - src/core/lib/surface/call_log_batch.cc
+  - src/core/lib/surface/channel.cc
+  - src/core/lib/surface/channel_init.cc
+  - src/core/lib/surface/channel_stack_type.cc
+  - src/core/lib/surface/completion_queue.cc
+  - src/core/lib/surface/completion_queue_factory.cc
+  - src/core/lib/surface/event_string.cc
+  - src/core/lib/surface/init_internally.cc
+  - src/core/lib/surface/lame_client.cc
+  - src/core/lib/surface/metadata_array.cc
+  - src/core/lib/surface/validate_metadata.cc
+  - src/core/lib/surface/version.cc
+  - src/core/lib/surface/wait_for_cq_end_op.cc
+  - src/core/lib/transport/batch_builder.cc
+  - src/core/lib/transport/call_arena_allocator.cc
+  - src/core/lib/transport/call_filters.cc
+  - src/core/lib/transport/call_final_info.cc
+  - src/core/lib/transport/call_spine.cc
+  - src/core/lib/transport/connectivity_state.cc
+  - src/core/lib/transport/error_utils.cc
+  - src/core/lib/transport/handshaker_registry.cc
+  - src/core/lib/transport/interception_chain.cc
+  - src/core/lib/transport/message.cc
+  - src/core/lib/transport/metadata.cc
+  - src/core/lib/transport/metadata_batch.cc
+  - src/core/lib/transport/parsed_metadata.cc
+  - src/core/lib/transport/status_conversion.cc
+  - src/core/lib/transport/timeout_encoding.cc
+  - src/core/lib/transport/transport.cc
+  - src/core/lib/transport/transport_op_string.cc
+  - src/core/lib/uri/uri_parser.cc
+  - src/core/load_balancing/lb_policy.cc
+  - src/core/load_balancing/lb_policy_registry.cc
+  - src/core/resolver/endpoint_addresses.cc
+  - src/core/resolver/resolver.cc
+  - src/core/resolver/resolver_registry.cc
+  - src/core/service_config/service_config_parser.cc
+  - src/core/tsi/alts/handshaker/transport_security_common_api.cc
+  - test/core/transport/interception_chain_test.cc
+  - third_party/upb/upb/mini_descriptor/build_enum.c
+  - third_party/upb/upb/mini_descriptor/decode.c
+  - third_party/upb/upb/mini_descriptor/internal/base92.c
+  - third_party/upb/upb/mini_descriptor/internal/encode.c
+  - third_party/upb/upb/mini_descriptor/link.c
+  - third_party/upb/upb/wire/decode.c
+  - third_party/upb/upb/wire/encode.c
+  - third_party/upb/upb/wire/eps_copy_input_stream.c
+  - third_party/upb/upb/wire/internal/decode_fast.c
+  - third_party/upb/upb/wire/reader.c
+  deps:
+  - gtest
+  - utf8_range_lib
+  - upb_message_lib
+  - z
+  - absl/base:config
+  - absl/base:no_destructor
+  - absl/cleanup:cleanup
+  - absl/container:flat_hash_map
+  - absl/container:inlined_vector
+  - absl/functional:function_ref
+  - absl/hash:hash
+  - absl/meta:type_traits
+  - absl/status:statusor
+  - absl/types:span
+  - absl/utility:utility
+  - cares
+  - gpr
+  - address_sorting
+  uses_polling: false
 - name: interceptor_list_test
   gtest: true
   build: test
@@ -13274,6 +13869,7 @@ targets:
   - src/core/lib/promise/map.h
   - src/core/lib/promise/observable.h
   - src/core/lib/promise/poll.h
+  - test/core/promise/poll_matcher.h
   src:
   - src/core/lib/promise/activity.cc
   - test/core/promise/observable_test.cc
diff --git a/config.m4 b/config.m4
index be7973006b8..2c5894bb9f5 100644
--- a/config.m4
+++ b/config.m4
@@ -781,9 +781,9 @@ if test "$PHP_GRPC" != "no"; then
     src/core/lib/surface/wait_for_cq_end_op.cc \
     src/core/lib/transport/batch_builder.cc \
     src/core/lib/transport/bdp_estimator.cc \
+    src/core/lib/transport/call_arena_allocator.cc \
     src/core/lib/transport/call_filters.cc \
     src/core/lib/transport/call_final_info.cc \
-    src/core/lib/transport/call_size_estimator.cc \
     src/core/lib/transport/call_spine.cc \
     src/core/lib/transport/connectivity_state.cc \
     src/core/lib/transport/endpoint_info_handshaker.cc \
diff --git a/config.w32 b/config.w32
index 3ab3dbfdf22..5e407c53995 100644
--- a/config.w32
+++ b/config.w32
@@ -746,9 +746,9 @@ if (PHP_GRPC != "no") {
     "src\\core\\lib\\surface\\wait_for_cq_end_op.cc " +
     "src\\core\\lib\\transport\\batch_builder.cc " +
     "src\\core\\lib\\transport\\bdp_estimator.cc " +
+    "src\\core\\lib\\transport\\call_arena_allocator.cc " +
     "src\\core\\lib\\transport\\call_filters.cc " +
     "src\\core\\lib\\transport\\call_final_info.cc " +
-    "src\\core\\lib\\transport\\call_size_estimator.cc " +
     "src\\core\\lib\\transport\\call_spine.cc " +
     "src\\core\\lib\\transport\\connectivity_state.cc " +
     "src\\core\\lib\\transport\\endpoint_info_handshaker.cc " +
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index 85099db02ee..a22f9661f96 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -1241,9 +1241,9 @@ Pod::Spec.new do |s|
                       'src/core/lib/surface/wait_for_cq_end_op.h',
                       'src/core/lib/transport/batch_builder.h',
                       'src/core/lib/transport/bdp_estimator.h',
+                      'src/core/lib/transport/call_arena_allocator.h',
                       'src/core/lib/transport/call_filters.h',
                       'src/core/lib/transport/call_final_info.h',
-                      'src/core/lib/transport/call_size_estimator.h',
                       'src/core/lib/transport/call_spine.h',
                       'src/core/lib/transport/connectivity_state.h',
                       'src/core/lib/transport/custom_metadata.h',
@@ -2512,9 +2512,9 @@ Pod::Spec.new do |s|
                               'src/core/lib/surface/wait_for_cq_end_op.h',
                               'src/core/lib/transport/batch_builder.h',
                               'src/core/lib/transport/bdp_estimator.h',
+                              'src/core/lib/transport/call_arena_allocator.h',
                               'src/core/lib/transport/call_filters.h',
                               'src/core/lib/transport/call_final_info.h',
-                              'src/core/lib/transport/call_size_estimator.h',
                               'src/core/lib/transport/call_spine.h',
                               'src/core/lib/transport/connectivity_state.h',
                               'src/core/lib/transport/custom_metadata.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 0d69b0c30d4..623acc21059 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -1915,12 +1915,12 @@ Pod::Spec.new do |s|
                       'src/core/lib/transport/batch_builder.h',
                       'src/core/lib/transport/bdp_estimator.cc',
                       'src/core/lib/transport/bdp_estimator.h',
+                      'src/core/lib/transport/call_arena_allocator.cc',
+                      'src/core/lib/transport/call_arena_allocator.h',
                       'src/core/lib/transport/call_filters.cc',
                       'src/core/lib/transport/call_filters.h',
                       'src/core/lib/transport/call_final_info.cc',
                       'src/core/lib/transport/call_final_info.h',
-                      'src/core/lib/transport/call_size_estimator.cc',
-                      'src/core/lib/transport/call_size_estimator.h',
                       'src/core/lib/transport/call_spine.cc',
                       'src/core/lib/transport/call_spine.h',
                       'src/core/lib/transport/connectivity_state.cc',
@@ -3291,9 +3291,9 @@ Pod::Spec.new do |s|
                               'src/core/lib/surface/wait_for_cq_end_op.h',
                               'src/core/lib/transport/batch_builder.h',
                               'src/core/lib/transport/bdp_estimator.h',
+                              'src/core/lib/transport/call_arena_allocator.h',
                               'src/core/lib/transport/call_filters.h',
                               'src/core/lib/transport/call_final_info.h',
-                              'src/core/lib/transport/call_size_estimator.h',
                               'src/core/lib/transport/call_spine.h',
                               'src/core/lib/transport/connectivity_state.h',
                               'src/core/lib/transport/custom_metadata.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 3c714dd2565..caebeafb099 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -1805,12 +1805,12 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/lib/transport/batch_builder.h )
   s.files += %w( src/core/lib/transport/bdp_estimator.cc )
   s.files += %w( src/core/lib/transport/bdp_estimator.h )
+  s.files += %w( src/core/lib/transport/call_arena_allocator.cc )
+  s.files += %w( src/core/lib/transport/call_arena_allocator.h )
   s.files += %w( src/core/lib/transport/call_filters.cc )
   s.files += %w( src/core/lib/transport/call_filters.h )
   s.files += %w( src/core/lib/transport/call_final_info.cc )
   s.files += %w( src/core/lib/transport/call_final_info.h )
-  s.files += %w( src/core/lib/transport/call_size_estimator.cc )
-  s.files += %w( src/core/lib/transport/call_size_estimator.h )
   s.files += %w( src/core/lib/transport/call_spine.cc )
   s.files += %w( src/core/lib/transport/call_spine.h )
   s.files += %w( src/core/lib/transport/connectivity_state.cc )
diff --git a/package.xml b/package.xml
index cd1737e1450..8c820cd3fd0 100644
--- a/package.xml
+++ b/package.xml
@@ -1787,12 +1787,12 @@
     <file baseinstalldir="/" name="src/core/lib/transport/batch_builder.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/bdp_estimator.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/bdp_estimator.h" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/call_arena_allocator.cc" role="src" />
+    <file baseinstalldir="/" name="src/core/lib/transport/call_arena_allocator.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/call_filters.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/call_filters.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/call_final_info.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/call_final_info.h" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/transport/call_size_estimator.cc" role="src" />
-    <file baseinstalldir="/" name="src/core/lib/transport/call_size_estimator.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/call_spine.cc" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/call_spine.h" role="src" />
     <file baseinstalldir="/" name="src/core/lib/transport/connectivity_state.cc" role="src" />
diff --git a/src/core/BUILD b/src/core/BUILD
index 8f0c0a013d5..2381f637791 100644
--- a/src/core/BUILD
+++ b/src/core/BUILD
@@ -7255,6 +7255,25 @@ grpc_cc_library(
     ],
 )
 
+grpc_cc_library(
+    name = "interception_chain",
+    srcs = [
+        "lib/transport/interception_chain.cc",
+    ],
+    hdrs = [
+        "lib/transport/interception_chain.h",
+    ],
+    deps = [
+        "call_destination",
+        "call_filters",
+        "call_spine",
+        "match",
+        "metadata",
+        "ref_counted",
+        "//:gpr_platform",
+    ],
+)
+
 grpc_cc_library(
     name = "call_destination",
     hdrs = [
@@ -7331,17 +7350,19 @@ grpc_cc_library(
     ],
     deps = [
         "1999",
+        "call_arena_allocator",
+        "call_filters",
         "for_each",
         "if",
         "latch",
         "message",
         "metadata",
         "pipe",
-        "prioritized_race",
         "promise_status",
         "status_flag",
         "try_seq",
         "//:gpr",
+        "//:legacy_context",
         "//:promise",
     ],
 )
@@ -7405,14 +7426,19 @@ grpc_cc_library(
 )
 
 grpc_cc_library(
-    name = "call_size_estimator",
+    name = "call_arena_allocator",
     srcs = [
-        "lib/transport/call_size_estimator.cc",
+        "lib/transport/call_arena_allocator.cc",
     ],
     hdrs = [
-        "lib/transport/call_size_estimator.h",
+        "lib/transport/call_arena_allocator.h",
+    ],
+    deps = [
+        "arena",
+        "memory_quota",
+        "ref_counted",
+        "//:gpr_platform",
     ],
-    deps = ["//:gpr_platform"],
 )
 
 grpc_cc_library(
diff --git a/src/core/lib/channel/promise_based_filter.h b/src/core/lib/channel/promise_based_filter.h
index 491cbe9c144..32af82253f0 100644
--- a/src/core/lib/channel/promise_based_filter.h
+++ b/src/core/lib/channel/promise_based_filter.h
@@ -49,6 +49,7 @@
 #include "src/core/lib/event_engine/default_event_engine.h"
 #include "src/core/lib/event_engine/event_engine_context.h"  // IWYU pragma: keep
 #include "src/core/lib/gprpp/debug_location.h"
+#include "src/core/lib/gprpp/match.h"
 #include "src/core/lib/gprpp/time.h"
 #include "src/core/lib/iomgr/call_combiner.h"
 #include "src/core/lib/iomgr/closure.h"
@@ -84,12 +85,21 @@ class ChannelFilter {
   class Args {
    public:
     Args() : Args(nullptr, nullptr) {}
-    explicit Args(grpc_channel_stack* channel_stack,
-                  grpc_channel_element* channel_element)
-        : channel_stack_(channel_stack), channel_element_(channel_element) {}
+    Args(grpc_channel_stack* channel_stack,
+         grpc_channel_element* channel_element)
+        : impl_(ChannelStackBased{channel_stack, channel_element}) {}
+    // While we're moving to call-v3 we need to have access to
+    // grpc_channel_stack & friends here. That means that we can't rely on this
+    // type signature from interception_chain.h, which means that we need a way
+    // of constructing this object without naming it ===> implicit construction.
+    // TODO(ctiller): remove this once we're fully on call-v3
+    // NOLINTNEXTLINE(google-explicit-constructor)
+    Args(size_t instance_id) : impl_(V3Based{instance_id}) {}
 
     ABSL_DEPRECATED("Direct access to channel stack is deprecated")
-    grpc_channel_stack* channel_stack() const { return channel_stack_; }
+    grpc_channel_stack* channel_stack() const {
+      return absl::get<ChannelStackBased>(impl_).channel_stack;
+    }
 
     // Get the instance id of this filter.
     // This id is unique amongst all filters /of the same type/ and densely
@@ -99,14 +109,29 @@ class ChannelFilter {
     // This is useful for filters that need to store per-instance data in a
     // parallel data structure.
     size_t instance_id() const {
-      return grpc_channel_stack_filter_instance_number(channel_stack_,
-                                                       channel_element_);
+      return Match(
+          impl_,
+          [](const ChannelStackBased& cs) {
+            return grpc_channel_stack_filter_instance_number(
+                cs.channel_stack, cs.channel_element);
+          },
+          [](const V3Based& v3) { return v3.instance_id; });
     }
 
    private:
     friend class ChannelFilter;
-    grpc_channel_stack* channel_stack_;
-    grpc_channel_element* channel_element_;
+
+    struct ChannelStackBased {
+      grpc_channel_stack* channel_stack;
+      grpc_channel_element* channel_element;
+    };
+
+    struct V3Based {
+      size_t instance_id;
+    };
+
+    using Impl = absl::variant<ChannelStackBased, V3Based>;
+    Impl impl_;
   };
 
   // Perform post-initialization step (if any).
diff --git a/src/core/lib/promise/detail/seq_state.h b/src/core/lib/promise/detail/seq_state.h
index 604114af4ed..f22b312aba4 100644
--- a/src/core/lib/promise/detail/seq_state.h
+++ b/src/core/lib/promise/detail/seq_state.h
@@ -143,14 +143,14 @@ struct SeqState<Traits, P, F0> {
     switch (state) {
       case State::kState0: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 1/2", this);
         }
         auto result = prior.current_promise();
         PromiseResult0* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 1/2 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits0::IsOk(*p)
@@ -176,12 +176,12 @@ struct SeqState<Traits, P, F0> {
       default:
       case State::kState1: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 2/2", this);
         }
         auto result = current_promise();
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: poll step 2/2 gets %s", this,
                   result.ready() ? "ready" : "pending");
         }
@@ -286,14 +286,14 @@ struct SeqState<Traits, P, F0, F1> {
     switch (state) {
       case State::kState0: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 1/3", this);
         }
         auto result = prior.prior.current_promise();
         PromiseResult0* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 1/3 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits0::IsOk(*p)
@@ -318,14 +318,14 @@ struct SeqState<Traits, P, F0, F1> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState1: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 2/3", this);
         }
         auto result = prior.current_promise();
         PromiseResult1* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 2/3 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits1::IsOk(*p)
@@ -351,12 +351,12 @@ struct SeqState<Traits, P, F0, F1> {
       default:
       case State::kState2: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 3/3", this);
         }
         auto result = current_promise();
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: poll step 3/3 gets %s", this,
                   result.ready() ? "ready" : "pending");
         }
@@ -488,14 +488,14 @@ struct SeqState<Traits, P, F0, F1, F2> {
     switch (state) {
       case State::kState0: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 1/4", this);
         }
         auto result = prior.prior.prior.current_promise();
         PromiseResult0* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 1/4 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits0::IsOk(*p)
@@ -520,14 +520,14 @@ struct SeqState<Traits, P, F0, F1, F2> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState1: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 2/4", this);
         }
         auto result = prior.prior.current_promise();
         PromiseResult1* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 2/4 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits1::IsOk(*p)
@@ -552,14 +552,14 @@ struct SeqState<Traits, P, F0, F1, F2> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState2: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 3/4", this);
         }
         auto result = prior.current_promise();
         PromiseResult2* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 3/4 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits2::IsOk(*p)
@@ -585,12 +585,12 @@ struct SeqState<Traits, P, F0, F1, F2> {
       default:
       case State::kState3: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 4/4", this);
         }
         auto result = current_promise();
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: poll step 4/4 gets %s", this,
                   result.ready() ? "ready" : "pending");
         }
@@ -750,14 +750,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3> {
     switch (state) {
       case State::kState0: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 1/5", this);
         }
         auto result = prior.prior.prior.prior.current_promise();
         PromiseResult0* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 1/5 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits0::IsOk(*p)
@@ -782,14 +782,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState1: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 2/5", this);
         }
         auto result = prior.prior.prior.current_promise();
         PromiseResult1* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 2/5 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits1::IsOk(*p)
@@ -814,14 +814,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState2: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 3/5", this);
         }
         auto result = prior.prior.current_promise();
         PromiseResult2* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 3/5 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits2::IsOk(*p)
@@ -846,14 +846,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState3: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 4/5", this);
         }
         auto result = prior.current_promise();
         PromiseResult3* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 4/5 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits3::IsOk(*p)
@@ -879,12 +879,12 @@ struct SeqState<Traits, P, F0, F1, F2, F3> {
       default:
       case State::kState4: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 5/5", this);
         }
         auto result = current_promise();
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: poll step 5/5 gets %s", this,
                   result.ready() ? "ready" : "pending");
         }
@@ -1081,14 +1081,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4> {
     switch (state) {
       case State::kState0: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 1/6", this);
         }
         auto result = prior.prior.prior.prior.prior.current_promise();
         PromiseResult0* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 1/6 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits0::IsOk(*p)
@@ -1114,14 +1114,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState1: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 2/6", this);
         }
         auto result = prior.prior.prior.prior.current_promise();
         PromiseResult1* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 2/6 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits1::IsOk(*p)
@@ -1146,14 +1146,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState2: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 3/6", this);
         }
         auto result = prior.prior.prior.current_promise();
         PromiseResult2* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 3/6 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits2::IsOk(*p)
@@ -1178,14 +1178,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState3: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 4/6", this);
         }
         auto result = prior.prior.current_promise();
         PromiseResult3* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 4/6 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits3::IsOk(*p)
@@ -1210,14 +1210,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState4: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 5/6", this);
         }
         auto result = prior.current_promise();
         PromiseResult4* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 5/6 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits4::IsOk(*p)
@@ -1243,12 +1243,12 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4> {
       default:
       case State::kState5: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 6/6", this);
         }
         auto result = current_promise();
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: poll step 6/6 gets %s", this,
                   result.ready() ? "ready" : "pending");
         }
@@ -1477,14 +1477,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5> {
     switch (state) {
       case State::kState0: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 1/7", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.current_promise();
         PromiseResult0* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 1/7 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits0::IsOk(*p)
@@ -1510,14 +1510,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState1: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 2/7", this);
         }
         auto result = prior.prior.prior.prior.prior.current_promise();
         PromiseResult1* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 2/7 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits1::IsOk(*p)
@@ -1543,14 +1543,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState2: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 3/7", this);
         }
         auto result = prior.prior.prior.prior.current_promise();
         PromiseResult2* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 3/7 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits2::IsOk(*p)
@@ -1575,14 +1575,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState3: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 4/7", this);
         }
         auto result = prior.prior.prior.current_promise();
         PromiseResult3* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 4/7 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits3::IsOk(*p)
@@ -1607,14 +1607,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState4: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 5/7", this);
         }
         auto result = prior.prior.current_promise();
         PromiseResult4* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 5/7 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits4::IsOk(*p)
@@ -1639,14 +1639,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState5: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 6/7", this);
         }
         auto result = prior.current_promise();
         PromiseResult5* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 6/7 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits5::IsOk(*p)
@@ -1672,12 +1672,12 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5> {
       default:
       case State::kState6: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 7/7", this);
         }
         auto result = current_promise();
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: poll step 7/7 gets %s", this,
                   result.ready() ? "ready" : "pending");
         }
@@ -1939,7 +1939,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6> {
     switch (state) {
       case State::kState0: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 1/8", this);
         }
         auto result =
@@ -1947,7 +1947,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6> {
         PromiseResult0* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 1/8 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits0::IsOk(*p)
@@ -1974,14 +1974,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState1: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 2/8", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.current_promise();
         PromiseResult1* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 2/8 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits1::IsOk(*p)
@@ -2007,14 +2007,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState2: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 3/8", this);
         }
         auto result = prior.prior.prior.prior.prior.current_promise();
         PromiseResult2* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 3/8 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits2::IsOk(*p)
@@ -2040,14 +2040,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState3: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 4/8", this);
         }
         auto result = prior.prior.prior.prior.current_promise();
         PromiseResult3* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 4/8 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits3::IsOk(*p)
@@ -2072,14 +2072,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState4: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 5/8", this);
         }
         auto result = prior.prior.prior.current_promise();
         PromiseResult4* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 5/8 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits4::IsOk(*p)
@@ -2104,14 +2104,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState5: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 6/8", this);
         }
         auto result = prior.prior.current_promise();
         PromiseResult5* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 6/8 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits5::IsOk(*p)
@@ -2136,14 +2136,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState6: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 7/8", this);
         }
         auto result = prior.current_promise();
         PromiseResult6* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 7/8 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits6::IsOk(*p)
@@ -2169,12 +2169,12 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6> {
       default:
       case State::kState7: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 8/8", this);
         }
         auto result = current_promise();
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: poll step 8/8 gets %s", this,
                   result.ready() ? "ready" : "pending");
         }
@@ -2470,7 +2470,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7> {
     switch (state) {
       case State::kState0: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 1/9", this);
         }
         auto result =
@@ -2478,7 +2478,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7> {
         PromiseResult0* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 1/9 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits0::IsOk(*p)
@@ -2506,7 +2506,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState1: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 2/9", this);
         }
         auto result =
@@ -2514,7 +2514,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7> {
         PromiseResult1* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 2/9 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits1::IsOk(*p)
@@ -2541,14 +2541,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState2: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 3/9", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.current_promise();
         PromiseResult2* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 3/9 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits2::IsOk(*p)
@@ -2574,14 +2574,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState3: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 4/9", this);
         }
         auto result = prior.prior.prior.prior.prior.current_promise();
         PromiseResult3* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 4/9 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits3::IsOk(*p)
@@ -2607,14 +2607,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState4: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 5/9", this);
         }
         auto result = prior.prior.prior.prior.current_promise();
         PromiseResult4* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 5/9 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits4::IsOk(*p)
@@ -2639,14 +2639,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState5: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 6/9", this);
         }
         auto result = prior.prior.prior.current_promise();
         PromiseResult5* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 6/9 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits5::IsOk(*p)
@@ -2671,14 +2671,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState6: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 7/9", this);
         }
         auto result = prior.prior.current_promise();
         PromiseResult6* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 7/9 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits6::IsOk(*p)
@@ -2703,14 +2703,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState7: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 8/9", this);
         }
         auto result = prior.current_promise();
         PromiseResult7* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 8/9 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits7::IsOk(*p)
@@ -2736,12 +2736,12 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7> {
       default:
       case State::kState8: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 9/9", this);
         }
         auto result = current_promise();
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: poll step 9/9 gets %s", this,
                   result.ready() ? "ready" : "pending");
         }
@@ -3076,7 +3076,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8> {
     switch (state) {
       case State::kState0: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 1/10", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.prior.prior.prior
@@ -3084,7 +3084,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8> {
         PromiseResult0* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 1/10 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits0::IsOk(*p)
@@ -3114,7 +3114,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState1: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 2/10", this);
         }
         auto result =
@@ -3122,7 +3122,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8> {
         PromiseResult1* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 2/10 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits1::IsOk(*p)
@@ -3150,7 +3150,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState2: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 3/10", this);
         }
         auto result =
@@ -3158,7 +3158,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8> {
         PromiseResult2* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 3/10 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits2::IsOk(*p)
@@ -3185,14 +3185,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState3: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 4/10", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.current_promise();
         PromiseResult3* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 4/10 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits3::IsOk(*p)
@@ -3218,14 +3218,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState4: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 5/10", this);
         }
         auto result = prior.prior.prior.prior.prior.current_promise();
         PromiseResult4* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 5/10 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits4::IsOk(*p)
@@ -3251,14 +3251,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState5: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 6/10", this);
         }
         auto result = prior.prior.prior.prior.current_promise();
         PromiseResult5* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 6/10 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits5::IsOk(*p)
@@ -3283,14 +3283,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState6: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 7/10", this);
         }
         auto result = prior.prior.prior.current_promise();
         PromiseResult6* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 7/10 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits6::IsOk(*p)
@@ -3315,14 +3315,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState7: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 8/10", this);
         }
         auto result = prior.prior.current_promise();
         PromiseResult7* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 8/10 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits7::IsOk(*p)
@@ -3347,14 +3347,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState8: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 9/10", this);
         }
         auto result = prior.current_promise();
         PromiseResult8* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 9/10 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits8::IsOk(*p)
@@ -3380,12 +3380,12 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8> {
       default:
       case State::kState9: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 10/10", this);
         }
         auto result = current_promise();
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: poll step 10/10 gets %s", this,
                   result.ready() ? "ready" : "pending");
         }
@@ -3758,7 +3758,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9> {
     switch (state) {
       case State::kState0: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 1/11", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.prior.prior.prior
@@ -3766,7 +3766,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9> {
         PromiseResult0* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 1/11 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits0::IsOk(*p)
@@ -3797,7 +3797,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState1: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 2/11", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.prior.prior.prior
@@ -3805,7 +3805,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9> {
         PromiseResult1* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 2/11 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits1::IsOk(*p)
@@ -3835,7 +3835,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState2: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 3/11", this);
         }
         auto result =
@@ -3843,7 +3843,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9> {
         PromiseResult2* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 3/11 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits2::IsOk(*p)
@@ -3871,7 +3871,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState3: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 4/11", this);
         }
         auto result =
@@ -3879,7 +3879,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9> {
         PromiseResult3* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 4/11 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits3::IsOk(*p)
@@ -3906,14 +3906,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState4: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 5/11", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.current_promise();
         PromiseResult4* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 5/11 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits4::IsOk(*p)
@@ -3939,14 +3939,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState5: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 6/11", this);
         }
         auto result = prior.prior.prior.prior.prior.current_promise();
         PromiseResult5* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 6/11 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits5::IsOk(*p)
@@ -3972,14 +3972,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState6: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 7/11", this);
         }
         auto result = prior.prior.prior.prior.current_promise();
         PromiseResult6* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 7/11 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits6::IsOk(*p)
@@ -4004,14 +4004,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState7: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 8/11", this);
         }
         auto result = prior.prior.prior.current_promise();
         PromiseResult7* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 8/11 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits7::IsOk(*p)
@@ -4036,14 +4036,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState8: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 9/11", this);
         }
         auto result = prior.prior.current_promise();
         PromiseResult8* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 9/11 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits8::IsOk(*p)
@@ -4068,14 +4068,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState9: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 10/11", this);
         }
         auto result = prior.current_promise();
         PromiseResult9* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 10/11 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits9::IsOk(*p)
@@ -4101,12 +4101,12 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9> {
       default:
       case State::kState10: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 11/11", this);
         }
         auto result = current_promise();
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: poll step 11/11 gets %s", this,
                   result.ready() ? "ready" : "pending");
         }
@@ -4517,7 +4517,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
     switch (state) {
       case State::kState0: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 1/12", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.prior.prior.prior
@@ -4525,7 +4525,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
         PromiseResult0* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 1/12 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits0::IsOk(*p)
@@ -4556,7 +4556,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState1: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 2/12", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.prior.prior.prior
@@ -4564,7 +4564,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
         PromiseResult1* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 2/12 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits1::IsOk(*p)
@@ -4595,7 +4595,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState2: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 3/12", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.prior.prior.prior
@@ -4603,7 +4603,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
         PromiseResult2* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 3/12 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits2::IsOk(*p)
@@ -4633,7 +4633,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState3: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 4/12", this);
         }
         auto result =
@@ -4641,7 +4641,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
         PromiseResult3* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 4/12 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits3::IsOk(*p)
@@ -4669,7 +4669,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState4: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 5/12", this);
         }
         auto result =
@@ -4677,7 +4677,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
         PromiseResult4* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 5/12 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits4::IsOk(*p)
@@ -4704,14 +4704,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState5: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 6/12", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.current_promise();
         PromiseResult5* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 6/12 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits5::IsOk(*p)
@@ -4737,14 +4737,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState6: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 7/12", this);
         }
         auto result = prior.prior.prior.prior.prior.current_promise();
         PromiseResult6* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 7/12 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits6::IsOk(*p)
@@ -4770,14 +4770,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState7: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 8/12", this);
         }
         auto result = prior.prior.prior.prior.current_promise();
         PromiseResult7* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 8/12 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits7::IsOk(*p)
@@ -4802,14 +4802,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState8: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 9/12", this);
         }
         auto result = prior.prior.prior.current_promise();
         PromiseResult8* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 9/12 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits8::IsOk(*p)
@@ -4834,14 +4834,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState9: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 10/12", this);
         }
         auto result = prior.prior.current_promise();
         PromiseResult9* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 10/12 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits9::IsOk(*p)
@@ -4866,14 +4866,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState10: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 11/12", this);
         }
         auto result = prior.current_promise();
         PromiseResult10* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 11/12 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits10::IsOk(*p)
@@ -4899,12 +4899,12 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10> {
       default:
       case State::kState11: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 12/12", this);
         }
         auto result = current_promise();
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: poll step 12/12 gets %s", this,
                   result.ready() ? "ready" : "pending");
         }
@@ -5356,7 +5356,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
     switch (state) {
       case State::kState0: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 1/13", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.prior.prior.prior
@@ -5364,7 +5364,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         PromiseResult0* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 1/13 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits0::IsOk(*p)
@@ -5395,7 +5395,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState1: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 2/13", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.prior.prior.prior
@@ -5403,7 +5403,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         PromiseResult1* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 2/13 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits1::IsOk(*p)
@@ -5434,7 +5434,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState2: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 3/13", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.prior.prior.prior
@@ -5442,7 +5442,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         PromiseResult2* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 3/13 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits2::IsOk(*p)
@@ -5473,7 +5473,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState3: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 4/13", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.prior.prior.prior
@@ -5481,7 +5481,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         PromiseResult3* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 4/13 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits3::IsOk(*p)
@@ -5511,7 +5511,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState4: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 5/13", this);
         }
         auto result =
@@ -5519,7 +5519,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         PromiseResult4* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 5/13 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits4::IsOk(*p)
@@ -5547,7 +5547,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState5: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 6/13", this);
         }
         auto result =
@@ -5555,7 +5555,7 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         PromiseResult5* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 6/13 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits5::IsOk(*p)
@@ -5582,14 +5582,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState6: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 7/13", this);
         }
         auto result = prior.prior.prior.prior.prior.prior.current_promise();
         PromiseResult6* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 7/13 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits6::IsOk(*p)
@@ -5615,14 +5615,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState7: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 8/13", this);
         }
         auto result = prior.prior.prior.prior.prior.current_promise();
         PromiseResult7* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 8/13 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits7::IsOk(*p)
@@ -5648,14 +5648,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState8: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 9/13", this);
         }
         auto result = prior.prior.prior.prior.current_promise();
         PromiseResult8* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 9/13 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits8::IsOk(*p)
@@ -5680,14 +5680,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState9: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 10/13", this);
         }
         auto result = prior.prior.prior.current_promise();
         PromiseResult9* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 10/13 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits9::IsOk(*p)
@@ -5712,14 +5712,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState10: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 11/13", this);
         }
         auto result = prior.prior.current_promise();
         PromiseResult10* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 11/13 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits10::IsOk(*p)
@@ -5744,14 +5744,14 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
         ABSL_FALLTHROUGH_INTENDED;
       case State::kState11: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 12/13", this);
         }
         auto result = prior.current_promise();
         PromiseResult11* p = result.value_if_ready();
         if (grpc_trace_promise_primitives.enabled()) {
           gpr_log(
-              whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+              whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
               "seq[%p]: poll step 12/13 gets %s", this,
               p != nullptr
                   ? (PromiseResultTraits11::IsOk(*p)
@@ -5777,12 +5777,12 @@ struct SeqState<Traits, P, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11> {
       default:
       case State::kState12: {
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: begin poll step 13/13", this);
         }
         auto result = current_promise();
         if (grpc_trace_promise_primitives.enabled()) {
-          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_DEBUG,
+          gpr_log(whence.file(), whence.line(), GPR_LOG_SEVERITY_INFO,
                   "seq[%p]: poll step 13/13 gets %s", this,
                   result.ready() ? "ready" : "pending");
         }
diff --git a/src/core/lib/promise/for_each.h b/src/core/lib/promise/for_each.h
index 82322add349..529dde62256 100644
--- a/src/core/lib/promise/for_each.h
+++ b/src/core/lib/promise/for_each.h
@@ -109,8 +109,10 @@ class ForEach {
  public:
   using Result =
       typename PollTraits<decltype(std::declval<ActionPromise>()())>::Type;
-  ForEach(Reader reader, Action action)
-      : reader_(std::move(reader)), action_factory_(std::move(action)) {
+  ForEach(Reader reader, Action action, DebugLocation whence = {})
+      : reader_(std::move(reader)),
+        action_factory_(std::move(action)),
+        whence_(whence) {
     Construct(&reader_next_, reader_.Next());
   }
   ~ForEach() {
@@ -125,7 +127,8 @@ class ForEach {
   ForEach& operator=(const ForEach&) = delete;
   ForEach(ForEach&& other) noexcept
       : reader_(std::move(other.reader_)),
-        action_factory_(std::move(other.action_factory_)) {
+        action_factory_(std::move(other.action_factory_)),
+        whence_(other.whence_) {
     GPR_DEBUG_ASSERT(reading_next_);
     GPR_DEBUG_ASSERT(other.reading_next_);
     Construct(&reader_next_, std::move(other.reader_next_));
@@ -136,6 +139,7 @@ class ForEach {
     reader_ = std::move(other.reader_);
     action_factory_ = std::move(other.action_factory_);
     reader_next_ = std::move(other.reader_next_);
+    whence_ = other.whence_;
     return *this;
   }
 
@@ -154,7 +158,8 @@ class ForEach {
 
   std::string DebugTag() {
     return absl::StrCat(GetContext<Activity>()->DebugTag(), " FOR_EACH[0x",
-                        reinterpret_cast<uintptr_t>(this), "]: ");
+                        reinterpret_cast<uintptr_t>(this), "@", whence_.file(),
+                        ":", whence_.line(), "]: ");
   }
 
   Poll<Result> PollReaderNext() {
@@ -215,6 +220,7 @@ class ForEach {
 
   GPR_NO_UNIQUE_ADDRESS Reader reader_;
   GPR_NO_UNIQUE_ADDRESS ActionFactory action_factory_;
+  GPR_NO_UNIQUE_ADDRESS DebugLocation whence_;
   bool reading_next_ = true;
   union {
     ReaderNext reader_next_;
@@ -226,9 +232,10 @@ class ForEach {
 
 /// For each item acquired by calling Reader::Next, run the promise Action.
 template <typename Reader, typename Action>
-for_each_detail::ForEach<Reader, Action> ForEach(Reader reader, Action action) {
+for_each_detail::ForEach<Reader, Action> ForEach(Reader reader, Action action,
+                                                 DebugLocation whence = {}) {
   return for_each_detail::ForEach<Reader, Action>(std::move(reader),
-                                                  std::move(action));
+                                                  std::move(action), whence);
 }
 
 }  // namespace grpc_core
diff --git a/src/core/lib/promise/party.cc b/src/core/lib/promise/party.cc
index 104201a3b2f..5d967a658e0 100644
--- a/src/core/lib/promise/party.cc
+++ b/src/core/lib/promise/party.cc
@@ -273,7 +273,7 @@ bool Party::RunOneParticipant(int i) {
   auto* participant = participants_[i].load(std::memory_order_acquire);
   if (participant == nullptr) {
     if (grpc_trace_promise_primitives.enabled()) {
-      gpr_log(GPR_DEBUG, "%s[party] wakeup %d already complete",
+      gpr_log(GPR_INFO, "%s[party] wakeup %d already complete",
               DebugTag().c_str(), i);
     }
     return false;
@@ -281,7 +281,7 @@ bool Party::RunOneParticipant(int i) {
   absl::string_view name;
   if (grpc_trace_promise_primitives.enabled()) {
     name = participant->name();
-    gpr_log(GPR_DEBUG, "%s[%s] begin job %d", DebugTag().c_str(),
+    gpr_log(GPR_INFO, "%s[%s] begin job %d", DebugTag().c_str(),
             std::string(name).c_str(), i);
   }
   // Poll the participant.
@@ -290,12 +290,12 @@ bool Party::RunOneParticipant(int i) {
   currently_polling_ = kNotPolling;
   if (done) {
     if (!name.empty()) {
-      gpr_log(GPR_DEBUG, "%s[%s] end poll and finish job %d",
-              DebugTag().c_str(), std::string(name).c_str(), i);
+      gpr_log(GPR_INFO, "%s[%s] end poll and finish job %d", DebugTag().c_str(),
+              std::string(name).c_str(), i);
     }
     participants_[i].store(nullptr, std::memory_order_relaxed);
   } else if (!name.empty()) {
-    gpr_log(GPR_DEBUG, "%s[%s] end poll", DebugTag().c_str(),
+    gpr_log(GPR_INFO, "%s[%s] end poll", DebugTag().c_str(),
             std::string(name).c_str());
   }
   return done;
@@ -306,7 +306,7 @@ void Party::AddParticipants(Participant** participants, size_t count) {
                                                        count](size_t* slots) {
     for (size_t i = 0; i < count; i++) {
       if (grpc_trace_party_state.enabled()) {
-        gpr_log(GPR_DEBUG,
+        gpr_log(GPR_INFO,
                 "Party %p                 AddParticipant: %s @ %" PRIdPTR,
                 &sync_, std::string(participants[i]->name()).c_str(), slots[i]);
       }
diff --git a/src/core/lib/surface/call.cc b/src/core/lib/surface/call.cc
index f7152abb340..01099d7a054 100644
--- a/src/core/lib/surface/call.cc
+++ b/src/core/lib/surface/call.cc
@@ -90,6 +90,7 @@
 #include "src/core/lib/promise/race.h"
 #include "src/core/lib/promise/seq.h"
 #include "src/core/lib/promise/status_flag.h"
+#include "src/core/lib/promise/try_seq.h"
 #include "src/core/lib/resource_quota/arena.h"
 #include "src/core/lib/slice/slice_buffer.h"
 #include "src/core/lib/slice/slice_internal.h"
@@ -2879,6 +2880,12 @@ class ClientPromiseBasedCall final : public PromiseBasedCall {
         return RefCountedPtr<WrappingCallSpine>(this);
       }
 
+      ClientMetadata& UnprocessedClientInitialMetadata() override {
+        Crash("not for v2");
+      }
+
+      void V2HackToStartCallWithoutACallFilterStack() override {}
+
      private:
       RefCount refs_;
       ClientPromiseBasedCall* const call_;
@@ -3764,6 +3771,12 @@ class ServerCallSpine final : public PipeBasedCallSpine,
     Crash("unimplemented");
   }
 
+  void V2HackToStartCallWithoutACallFilterStack() override {}
+
+  ClientMetadata& UnprocessedClientInitialMetadata() override {
+    Crash("not for v2");
+  }
+
   bool RunParty() override {
     ScopedContext ctx(this);
     return Party::RunParty();
diff --git a/src/core/lib/surface/legacy_channel.h b/src/core/lib/surface/legacy_channel.h
index 780de9f4fa9..3cf3fa0db22 100644
--- a/src/core/lib/surface/legacy_channel.h
+++ b/src/core/lib/surface/legacy_channel.h
@@ -39,7 +39,7 @@
 #include "src/core/lib/slice/slice.h"
 #include "src/core/lib/surface/channel.h"
 #include "src/core/lib/surface/channel_stack_type.h"
-#include "src/core/lib/transport/call_size_estimator.h"
+#include "src/core/lib/transport/call_arena_allocator.h"
 
 namespace grpc_core {
 
diff --git a/src/core/lib/transport/call_size_estimator.cc b/src/core/lib/transport/call_arena_allocator.cc
similarity index 96%
rename from src/core/lib/transport/call_size_estimator.cc
rename to src/core/lib/transport/call_arena_allocator.cc
index 0892fa9e9cc..a0bae7cd146 100644
--- a/src/core/lib/transport/call_size_estimator.cc
+++ b/src/core/lib/transport/call_arena_allocator.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/core/lib/transport/call_size_estimator.h"
+#include "src/core/lib/transport/call_arena_allocator.h"
 
 #include <algorithm>
 
diff --git a/src/core/lib/transport/call_size_estimator.h b/src/core/lib/transport/call_arena_allocator.h
similarity index 65%
rename from src/core/lib/transport/call_size_estimator.h
rename to src/core/lib/transport/call_arena_allocator.h
index 75ae1d7256f..1db02bf6902 100644
--- a/src/core/lib/transport/call_size_estimator.h
+++ b/src/core/lib/transport/call_arena_allocator.h
@@ -12,15 +12,20 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_CALL_SIZE_ESTIMATOR_H
-#define GRPC_SRC_CORE_LIB_TRANSPORT_CALL_SIZE_ESTIMATOR_H
+#ifndef GRPC_SRC_CORE_LIB_TRANSPORT_CALL_ARENA_ALLOCATOR_H
+#define GRPC_SRC_CORE_LIB_TRANSPORT_CALL_ARENA_ALLOCATOR_H
 
 #include <stddef.h>
 
 #include <atomic>
+#include <cstddef>
 
 #include <grpc/support/port_platform.h>
 
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/resource_quota/arena.h"
+#include "src/core/lib/resource_quota/memory_quota.h"
+
 namespace grpc_core {
 
 class CallSizeEstimator {
@@ -47,6 +52,22 @@ class CallSizeEstimator {
   std::atomic<size_t> call_size_estimate_;
 };
 
+class CallArenaAllocator : public RefCounted<CallArenaAllocator> {
+ public:
+  CallArenaAllocator(MemoryAllocator allocator, size_t initial_size)
+      : allocator_(std::move(allocator)), call_size_estimator_(initial_size) {}
+
+  Arena* MakeArena() {
+    return Arena::Create(call_size_estimator_.CallSizeEstimate(), &allocator_);
+  }
+
+  void Destroy(Arena* arena) { arena->Destroy(); }
+
+ private:
+  MemoryAllocator allocator_;
+  CallSizeEstimator call_size_estimator_;
+};
+
 }  // namespace grpc_core
 
-#endif  // GRPC_SRC_CORE_LIB_TRANSPORT_CALL_SIZE_ESTIMATOR_H
+#endif  // GRPC_SRC_CORE_LIB_TRANSPORT_CALL_ARENA_ALLOCATOR_H
diff --git a/src/core/lib/transport/call_destination.h b/src/core/lib/transport/call_destination.h
index e291bd703cb..2cf0f446d24 100644
--- a/src/core/lib/transport/call_destination.h
+++ b/src/core/lib/transport/call_destination.h
@@ -22,12 +22,33 @@
 
 namespace grpc_core {
 
-// CallDestination is responsible for the processing of a CallHandler.
-// It might be a transport, the server API, or a subchannel on the client (for
-// instance).
-class CallDestination : public Orphanable {
+// UnstartedCallDestination is responsible for starting an UnstartedCallHandler
+// and then processing operations on the resulting CallHandler.
+//
+// Examples of UnstartedCallDestinations include:
+// - a load-balanced call in the client channel
+// - a hijacking filter (see Interceptor)
+class UnstartedCallDestination
+    : public DualRefCounted<UnstartedCallDestination> {
+ public:
+  ~UnstartedCallDestination() override = default;
+  // Start a call. The UnstartedCallHandler will be consumed by the Destination
+  // and started.
+  // Must be called from the party owned by the call, eg the following must
+  // hold:
+  // GPR_ASSERT(GetContext<Activity>() == unstarted_call_handler.party());
+  virtual void StartCall(UnstartedCallHandler unstarted_call_handler) = 0;
+};
+
+// CallDestination is responsible for handling processing of an already started
+// call.
+//
+// Examples of CallDestinations include:
+// - a client transport
+// - the server API
+class CallDestination : public DualRefCounted<CallDestination> {
  public:
-  virtual void StartCall(CallHandler call_handler) = 0;
+  virtual void HandleCall(CallHandler unstarted_call_handler) = 0;
 };
 
 }  // namespace grpc_core
diff --git a/src/core/lib/transport/call_filters.cc b/src/core/lib/transport/call_filters.cc
index 5e3545ba6ce..c40ca8609e8 100644
--- a/src/core/lib/transport/call_filters.cc
+++ b/src/core/lib/transport/call_filters.cc
@@ -53,6 +53,7 @@ Poll<ResultOr<T>> OperationExecutor<T>::Start(
 
 template <typename T>
 Poll<ResultOr<T>> OperationExecutor<T>::InitStep(T input, void* call_data) {
+  GPR_ASSERT(input != nullptr);
   while (true) {
     if (ops_ == end_ops_) {
       return ResultOr<T>{std::move(input), nullptr};
@@ -216,9 +217,10 @@ void CallFilters::CancelDueToFailedPipeOperation(SourceLocation but_where) {
 }
 
 void CallFilters::PushServerTrailingMetadata(ServerMetadataHandle md) {
+  GPR_ASSERT(md != nullptr);
   if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_promise_primitives)) {
-    gpr_log(GPR_DEBUG, "%s Push server trailing metadata: %s into %s",
-            GetContext<Activity>()->DebugTag().c_str(),
+    gpr_log(GPR_INFO, "%s PushServerTrailingMetadata[%p]: %s into %s",
+            GetContext<Activity>()->DebugTag().c_str(), this,
             md->DebugString().c_str(), DebugString().c_str());
   }
   GPR_ASSERT(md != nullptr);
@@ -227,7 +229,7 @@ void CallFilters::PushServerTrailingMetadata(ServerMetadataHandle md) {
   client_initial_metadata_state_.CloseWithError();
   server_initial_metadata_state_.CloseSending();
   client_to_server_message_state_.CloseWithError();
-  server_to_client_message_state_.CloseWithError();
+  server_to_client_message_state_.CloseSending();
   server_trailing_metadata_waiter_.Wake();
 }
 
@@ -358,6 +360,10 @@ void filters_detail::PipeState::DropPush() {
     case ValueState::kReady:
     case ValueState::kProcessing:
     case ValueState::kWaiting:
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_promise_primitives)) {
+        gpr_log(GPR_INFO, "%p drop push in state %s", this,
+                DebugString().c_str());
+      }
       state_ = ValueState::kError;
       wait_recv_.Wake();
       break;
@@ -374,6 +380,10 @@ void filters_detail::PipeState::DropPull() {
     case ValueState::kReady:
     case ValueState::kProcessing:
     case ValueState::kWaiting:
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_promise_primitives)) {
+        gpr_log(GPR_INFO, "%p drop pull in state %s", this,
+                DebugString().c_str());
+      }
       state_ = ValueState::kError;
       wait_send_.Wake();
       break;
@@ -386,9 +396,12 @@ void filters_detail::PipeState::DropPull() {
 
 Poll<StatusFlag> filters_detail::PipeState::PollPush() {
   switch (state_) {
-    case ValueState::kIdle:
     // Read completed and new read started => we see waiting here
     case ValueState::kWaiting:
+      state_ = ValueState::kReady;
+      wait_recv_.Wake();
+      return wait_send_.pending();
+    case ValueState::kIdle:
     case ValueState::kClosed:
       return Success{};
     case ValueState::kQueued:
diff --git a/src/core/lib/transport/call_filters.h b/src/core/lib/transport/call_filters.h
index 0bd9a257314..b69b44a8df3 100644
--- a/src/core/lib/transport/call_filters.h
+++ b/src/core/lib/transport/call_filters.h
@@ -155,6 +155,10 @@ struct CallConstructor<FilterType,
 // Only one pointer can be set.
 template <typename T>
 struct ResultOr {
+  ResultOr(T ok, ServerMetadataHandle error)
+      : ok(std::move(ok)), error(std::move(error)) {
+    GPR_ASSERT((this->ok == nullptr) ^ (this->error == nullptr));
+  }
   T ok;
   ServerMetadataHandle error;
 };
@@ -1310,44 +1314,6 @@ class CallFilters {
     filters_detail::StackData data_;
   };
 
-  class NextMessage {
-   public:
-    NextMessage() : has_value_(false), cancelled_(false) {}
-    explicit NextMessage(MessageHandle value)
-        : has_value_(true), value_(std::move(value)) {}
-    explicit NextMessage(bool cancelled)
-        : has_value_(false), cancelled_(cancelled) {}
-    NextMessage(const NextMessage&) = delete;
-    NextMessage& operator=(const NextMessage&) = delete;
-    NextMessage(NextMessage&& other) noexcept = default;
-    NextMessage& operator=(NextMessage&& other) = default;
-
-    using value_type = MessageHandle;
-
-    void reset() {
-      has_value_ = false;
-      cancelled_ = false;
-      value_.reset();
-    }
-    bool has_value() const { return has_value_; }
-    const MessageHandle& value() const {
-      GPR_DEBUG_ASSERT(has_value_);
-      return value_;
-    }
-    MessageHandle& value() {
-      GPR_DEBUG_ASSERT(has_value_);
-      return value_;
-    }
-    const MessageHandle& operator*() const { return value(); }
-    MessageHandle& operator*() { return value(); }
-    bool cancelled() const { return !has_value_ && cancelled_; }
-
-   private:
-    bool has_value_;
-    bool cancelled_;
-    MessageHandle value_;
-  };
-
   explicit CallFilters(ClientMetadataHandle client_initial_metadata);
   ~CallFilters();
 
@@ -1422,12 +1388,21 @@ class CallFilters {
      public:
       Push(CallFilters* filters, T x)
           : filters_(filters), value_(std::move(x)) {
+        GPR_ASSERT(value_ != nullptr);
+        if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_promise_primitives)) {
+          gpr_log(GPR_INFO, "BeginPush[%p|%p]: %s", &state(), this,
+                  state().DebugString().c_str());
+        }
+        GPR_ASSERT(push_slot() == nullptr);
         state().BeginPush();
         push_slot() = this;
       }
       ~Push() {
         if (filters_ != nullptr) {
-          state().DropPush();
+          if (value_ != nullptr) {
+            state().DropPush();
+          }
+          GPR_ASSERT(push_slot() == this);
           push_slot() = nullptr;
         }
       }
@@ -1445,9 +1420,49 @@ class CallFilters {
 
       Push& operator=(Push&&) = delete;
 
-      Poll<StatusFlag> operator()() { return state().PollPush(); }
+      Poll<StatusFlag> operator()() {
+        if (value_ == nullptr) {
+          GPR_ASSERT(filters_ == nullptr);
+          if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_promise_primitives)) {
+            gpr_log(GPR_INFO, "Push[|%p]: already done", this);
+          }
+          return Success{};
+        }
+        if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_promise_primitives)) {
+          gpr_log(GPR_INFO, "Push[%p|%p]: %s", &state(), this,
+                  state().DebugString().c_str());
+        }
+        auto r = state().PollPush();
+        if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_promise_primitives)) {
+          if (r.pending()) {
+            gpr_log(GPR_INFO, "Push[%p|%p]: pending; %s", &state(), this,
+                    state().DebugString().c_str());
+          } else if (r.value().ok()) {
+            gpr_log(GPR_INFO, "Push[%p|%p]: success; %s", &state(), this,
+                    state().DebugString().c_str());
+          } else {
+            gpr_log(GPR_INFO, "Push[%p|%p]: failure; %s", &state(), this,
+                    state().DebugString().c_str());
+          }
+        }
+        if (r.ready()) {
+          push_slot() = nullptr;
+          filters_ = nullptr;
+        }
+        return r;
+      }
 
-      T TakeValue() { return std::move(value_); }
+      T TakeValue() {
+        if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_promise_primitives)) {
+          gpr_log(GPR_INFO, "Push[%p|%p]: take value; %s", &state(), this,
+                  state().DebugString().c_str());
+        }
+        GPR_ASSERT(value_ != nullptr);
+        GPR_ASSERT(filters_ != nullptr);
+        push_slot() = nullptr;
+        filters_ = nullptr;
+        return std::move(value_);
+      }
 
       absl::string_view DebugString() const {
         return value_ != nullptr ? " (not pulled)" : "";
@@ -1485,6 +1500,10 @@ class CallFilters {
       PullMaybe& operator=(PullMaybe&&) = delete;
 
       Poll<ValueOrFailure<absl::optional<T>>> operator()() {
+        if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_promise_primitives)) {
+          gpr_log(GPR_INFO, "PullMaybe[%p|%p]: %s executor:%d", &state(), this,
+                  state().DebugString().c_str(), executor_.IsRunning());
+        }
         if (executor_.IsRunning()) {
           auto c = state().PollClosed();
           if (c.ready() && c.value()) {
@@ -1544,23 +1563,36 @@ class CallFilters {
             executor_(std::move(other.executor_)) {}
       PullMessage& operator=(PullMessage&&) = delete;
 
-      Poll<NextMessage> operator()() {
+      Poll<ValueOrFailure<absl::optional<MessageHandle>>> operator()() {
+        GPR_ASSERT(filters_ != nullptr);
+        if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_promise_primitives)) {
+          gpr_log(GPR_INFO, "PullMessage[%p|%p]: %s executor:%d", &state(),
+                  this, state().DebugString().c_str(), executor_.IsRunning());
+        }
         if (executor_.IsRunning()) {
           auto c = state().PollClosed();
           if (c.ready() && c.value()) {
             filters_->CancelDueToFailedPipeOperation();
-            return NextMessage(true);
+            return Failure{};
           }
           return FinishOperationExecutor(executor_.Step(filters_->call_data_));
         }
         auto p = state().PollPull();
         auto* r = p.value_if_ready();
-        if (r == nullptr) return Pending{};
+        if (r == nullptr) {
+          if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_promise_primitives)) {
+            gpr_log(GPR_INFO, "PullMessage[%p] pending: %s executor:%d",
+                    &state(), state().DebugString().c_str(),
+                    executor_.IsRunning());
+          }
+          return Pending{};
+        }
         if (!r->ok()) {
           filters_->CancelDueToFailedPipeOperation();
-          return NextMessage(true);
+          return Failure{};
         }
-        if (!**r) return NextMessage(false);
+        if (!**r) return absl::nullopt;
+        GPR_ASSERT(filters_ != nullptr);
         return FinishOperationExecutor(executor_.Start(
             layout(), push()->TakeValue(), filters_->call_data_));
       }
@@ -1573,15 +1605,19 @@ class CallFilters {
         return &(filters_->stack_->data_.*layout_ptr);
       }
 
-      Poll<NextMessage> FinishOperationExecutor(
-          Poll<filters_detail::ResultOr<T>> p) {
+      Poll<ValueOrFailure<absl::optional<MessageHandle>>>
+      FinishOperationExecutor(Poll<filters_detail::ResultOr<T>> p) {
         auto* r = p.value_if_ready();
         if (r == nullptr) return Pending{};
         GPR_DEBUG_ASSERT(!executor_.IsRunning());
+        if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_promise_primitives)) {
+          gpr_log(GPR_INFO, "PullMessage[%p|%p] executor done: %s", &state(),
+                  this, state().DebugString().c_str());
+        }
         state().AckPull();
-        if (r->ok != nullptr) return NextMessage(std::move(r->ok));
+        if (r->ok != nullptr) return std::move(r->ok);
         filters_->PushServerTrailingMetadata(std::move(r->error));
-        return NextMessage(true);
+        return Failure{};
       }
 
       CallFilters* filters_;
@@ -1699,9 +1735,21 @@ class CallFilters {
         return std::move(filters_->server_trailing_metadata_);
       }
       // Otherwise we need to process it through all the filters.
-      return executor_.Start(&filters_->stack_->data_.server_trailing_metadata,
-                             std::move(filters_->server_trailing_metadata_),
-                             filters_->call_data_);
+      auto r = executor_.Start(
+          &filters_->stack_->data_.server_trailing_metadata,
+          std::move(filters_->server_trailing_metadata_), filters_->call_data_);
+      if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_promise_primitives)) {
+        if (r.pending()) {
+          gpr_log(GPR_INFO,
+                  "%s PullServerTrailingMetadata[%p]: Pending(but executing)",
+                  GetContext<Activity>()->DebugTag().c_str(), filters_);
+        } else {
+          gpr_log(GPR_INFO, "%s PullServerTrailingMetadata[%p]: Ready: %s",
+                  GetContext<Activity>()->DebugTag().c_str(), filters_,
+                  r.value()->DebugString().c_str());
+        }
+      }
+      return r;
     }
 
    private:
diff --git a/src/core/lib/transport/call_spine.cc b/src/core/lib/transport/call_spine.cc
index 6b8ce59916e..eb05608663f 100644
--- a/src/core/lib/transport/call_spine.cc
+++ b/src/core/lib/transport/call_spine.cc
@@ -16,6 +16,9 @@
 
 #include <grpc/support/port_platform.h>
 
+#include "src/core/lib/promise/for_each.h"
+#include "src/core/lib/promise/try_seq.h"
+
 namespace grpc_core {
 
 void ForwardCall(CallHandler call_handler, CallInitiator call_initiator) {
@@ -89,12 +92,14 @@ void ForwardCall(CallHandler call_handler, CallInitiator call_initiator) {
   });
 }
 
-CallInitiatorAndHandler MakeCall(
+CallInitiatorAndHandler MakeCallPair(
     ClientMetadataHandle client_initial_metadata,
     grpc_event_engine::experimental::EventEngine* event_engine, Arena* arena,
-    bool is_arena_owned) {
-  auto spine = CallSpine::Create(std::move(client_initial_metadata),
-                                 event_engine, arena, is_arena_owned);
+    RefCountedPtr<CallArenaAllocator> call_arena_allocator_if_arena_is_owned,
+    grpc_call_context_element* legacy_context) {
+  auto spine = CallSpine::Create(
+      std::move(client_initial_metadata), event_engine, arena,
+      std::move(call_arena_allocator_if_arena_is_owned), legacy_context);
   return {CallInitiator(spine), UnstartedCallHandler(spine)};
 }
 
diff --git a/src/core/lib/transport/call_spine.h b/src/core/lib/transport/call_spine.h
index 514c92c245d..2c81c2ff927 100644
--- a/src/core/lib/transport/call_spine.h
+++ b/src/core/lib/transport/call_spine.h
@@ -18,16 +18,16 @@
 #include <grpc/support/log.h>
 #include <grpc/support/port_platform.h>
 
+#include "src/core/lib/channel/context.h"
 #include "src/core/lib/promise/detail/status.h"
-#include "src/core/lib/promise/for_each.h"
 #include "src/core/lib/promise/if.h"
 #include "src/core/lib/promise/latch.h"
 #include "src/core/lib/promise/party.h"
 #include "src/core/lib/promise/pipe.h"
-#include "src/core/lib/promise/prioritized_race.h"
 #include "src/core/lib/promise/promise.h"
 #include "src/core/lib/promise/status_flag.h"
-#include "src/core/lib/promise/try_seq.h"
+#include "src/core/lib/transport/call_arena_allocator.h"
+#include "src/core/lib/transport/call_filters.h"
 #include "src/core/lib/transport/message.h"
 #include "src/core/lib/transport/metadata.h"
 
@@ -80,6 +80,8 @@ class CallSpineInterface {
   virtual Promise<StatusFlag> PushServerInitialMetadata(
       absl::optional<ServerMetadataHandle> md) = 0;
   virtual Promise<bool> WasCancelled() = 0;
+  virtual ClientMetadata& UnprocessedClientInitialMetadata() = 0;
+  virtual void V2HackToStartCallWithoutACallFilterStack() = 0;
 
   // Wrap a promise so that if it returns failure it automatically cancels
   // the rest of the call.
@@ -252,58 +254,149 @@ class PipeBasedCallSpine : public CallSpineInterface {
   }
 };
 
-class CallSpine final : public PipeBasedCallSpine, public Party {
+class CallSpine final : public CallSpineInterface, public Party {
  public:
   static RefCountedPtr<CallSpine> Create(
       ClientMetadataHandle client_initial_metadata,
       grpc_event_engine::experimental::EventEngine* event_engine, Arena* arena,
-      bool is_arena_owned) {
-    auto spine = RefCountedPtr<CallSpine>(
-        arena->New<CallSpine>(event_engine, arena, is_arena_owned));
-    spine->SpawnInfallible(
-        "push_client_initial_metadata",
-        [spine = spine.get(), client_initial_metadata = std::move(
-                                  client_initial_metadata)]() mutable {
-          return Map(spine->client_initial_metadata_.sender.Push(
-                         std::move(client_initial_metadata)),
-                     [](bool) { return Empty{}; });
-        });
-    return spine;
+      RefCountedPtr<CallArenaAllocator> call_arena_allocator_if_arena_is_owned,
+      grpc_call_context_element* legacy_context) {
+    return RefCountedPtr<CallSpine>(arena->New<CallSpine>(
+        std::move(client_initial_metadata), event_engine, arena,
+        std::move(call_arena_allocator_if_arena_is_owned), legacy_context));
+  }
+
+  ~CallSpine() override {
+    if (legacy_context_is_owned_) {
+      for (size_t i = 0; i < GRPC_CONTEXT_COUNT; i++) {
+        grpc_call_context_element& elem = legacy_context_[i];
+        if (elem.destroy != nullptr) elem.destroy(&elem);
+      }
+    }
   }
 
-  Pipe<ClientMetadataHandle>& client_initial_metadata() override {
-    return client_initial_metadata_;
-  }
-  Pipe<ServerMetadataHandle>& server_initial_metadata() override {
-    return server_initial_metadata_;
-  }
-  Pipe<MessageHandle>& client_to_server_messages() override {
-    return client_to_server_messages_;
-  }
-  Pipe<MessageHandle>& server_to_client_messages() override {
-    return server_to_client_messages_;
-  }
-  Latch<ServerMetadataHandle>& cancel_latch() override { return cancel_latch_; }
-  Latch<bool>& was_cancelled_latch() override { return was_cancelled_latch_; }
+  CallFilters& call_filters() { return call_filters_; }
+
   Party& party() override { return *this; }
+
   Arena* arena() override { return arena_; }
+
   void IncrementRefCount() override { Party::IncrementRefCount(); }
+
   void Unref() override { Party::Unref(); }
 
+  Promise<ValueOrFailure<absl::optional<ServerMetadataHandle>>>
+  PullServerInitialMetadata() override {
+    return call_filters().PullServerInitialMetadata();
+  }
+
+  Promise<ServerMetadataHandle> PullServerTrailingMetadata() override {
+    return call_filters().PullServerTrailingMetadata();
+  }
+
+  Promise<StatusFlag> PushClientToServerMessage(
+      MessageHandle message) override {
+    return call_filters().PushClientToServerMessage(std::move(message));
+  }
+
+  Promise<ValueOrFailure<absl::optional<MessageHandle>>>
+  PullClientToServerMessage() override {
+    return call_filters().PullClientToServerMessage();
+  }
+
+  Promise<StatusFlag> PushServerToClientMessage(
+      MessageHandle message) override {
+    return call_filters().PushServerToClientMessage(std::move(message));
+  }
+
+  Promise<ValueOrFailure<absl::optional<MessageHandle>>>
+  PullServerToClientMessage() override {
+    return call_filters().PullServerToClientMessage();
+  }
+
+  void PushServerTrailingMetadata(ServerMetadataHandle md) override {
+    call_filters().PushServerTrailingMetadata(std::move(md));
+  }
+
+  void FinishSends() override { call_filters().FinishClientToServerSends(); }
+
+  Promise<ValueOrFailure<ClientMetadataHandle>> PullClientInitialMetadata()
+      override {
+    return call_filters().PullClientInitialMetadata();
+  }
+
+  Promise<StatusFlag> PushServerInitialMetadata(
+      absl::optional<ServerMetadataHandle> md) override {
+    if (md.has_value()) {
+      return call_filters().PushServerInitialMetadata(std::move(*md));
+    } else {
+      call_filters().NoServerInitialMetadata();
+      return Immediate<StatusFlag>(Success{});
+    }
+  }
+
+  Promise<bool> WasCancelled() override {
+    return call_filters().WasCancelled();
+  }
+
+  ClientMetadata& UnprocessedClientInitialMetadata() override {
+    return *call_filters().unprocessed_client_initial_metadata();
+  }
+
+  // TODO(ctiller): re-evaluate legacy context apis
+  grpc_call_context_element& legacy_context(grpc_context_index index) const {
+    return legacy_context_[index];
+  }
+
+  grpc_call_context_element* legacy_context() { return legacy_context_; }
+
+  grpc_event_engine::experimental::EventEngine* event_engine() const override {
+    return event_engine_;
+  }
+
+  void V2HackToStartCallWithoutACallFilterStack() override {
+    CallFilters::StackBuilder empty_stack_builder;
+    call_filters().SetStack(empty_stack_builder.Build());
+  }
+
  private:
   friend class Arena;
-  CallSpine(grpc_event_engine::experimental::EventEngine* event_engine,
-            Arena* arena, bool is_arena_owned)
+  CallSpine(ClientMetadataHandle client_initial_metadata,
+            grpc_event_engine::experimental::EventEngine* event_engine,
+            Arena* arena,
+            RefCountedPtr<CallArenaAllocator> call_arena_allocator,
+            grpc_call_context_element* legacy_context)
       : Party(1),
+        call_filters_(std::move(client_initial_metadata)),
         arena_(arena),
-        is_arena_owned_(is_arena_owned),
-        event_engine_(event_engine) {}
+        event_engine_(event_engine),
+        call_arena_allocator_if_arena_is_owned_(
+            std::move(call_arena_allocator)) {
+    if (legacy_context == nullptr) {
+      legacy_context_ = static_cast<grpc_call_context_element*>(
+          arena->Alloc(sizeof(grpc_call_context_element) * GRPC_CONTEXT_COUNT));
+      memset(legacy_context_, 0,
+             sizeof(grpc_call_context_element) * GRPC_CONTEXT_COUNT);
+      legacy_context_is_owned_ = true;
+    } else {
+      legacy_context_ = legacy_context;
+      legacy_context_is_owned_ = false;
+    }
+  }
 
-  class ScopedContext : public ScopedActivity,
-                        public promise_detail::Context<Arena> {
+  class ScopedContext
+      : public ScopedActivity,
+        public promise_detail::Context<Arena>,
+        public promise_detail::Context<
+            grpc_event_engine::experimental::EventEngine>,
+        public promise_detail::Context<grpc_call_context_element> {
    public:
     explicit ScopedContext(CallSpine* spine)
-        : ScopedActivity(&spine->party()), Context<Arena>(spine->arena()) {}
+        : ScopedActivity(spine),
+          Context<Arena>(spine->arena_),
+          Context<grpc_event_engine::experimental::EventEngine>(
+              spine->event_engine()),
+          Context<grpc_call_context_element>(spine->legacy_context_) {}
   };
 
   bool RunParty() override {
@@ -312,35 +405,30 @@ class CallSpine final : public PipeBasedCallSpine, public Party {
   }
 
   void PartyOver() override {
-    Arena* a = arena();
+    Arena* a = arena_;
+    RefCountedPtr<CallArenaAllocator> call_arena_allocator_if_arena_is_owned =
+        std::move(call_arena_allocator_if_arena_is_owned_);
     {
       ScopedContext context(this);
       CancelRemainingParticipants();
       a->DestroyManagedNewObjects();
     }
     this->~CallSpine();
-    a->Destroy();
-  }
-
-  grpc_event_engine::experimental::EventEngine* event_engine() const override {
-    return event_engine_;
+    if (call_arena_allocator_if_arena_is_owned != nullptr) {
+      call_arena_allocator_if_arena_is_owned->Destroy(a);
+    }
   }
 
-  Arena* arena_;
-  bool is_arena_owned_;
-  // Initial metadata from client to server
-  Pipe<ClientMetadataHandle> client_initial_metadata_{arena()};
-  // Initial metadata from server to client
-  Pipe<ServerMetadataHandle> server_initial_metadata_{arena()};
-  // Messages travelling from the application to the transport.
-  Pipe<MessageHandle> client_to_server_messages_{arena()};
-  // Messages travelling from the transport to the application.
-  Pipe<MessageHandle> server_to_client_messages_{arena()};
-  // Latch that can be set to terminate the call
-  Latch<ServerMetadataHandle> cancel_latch_;
-  Latch<bool> was_cancelled_latch_;
+  // Call filters/pipes part of the spine
+  CallFilters call_filters_;
+  Arena* const arena_;
   // Event engine associated with this call
   grpc_event_engine::experimental::EventEngine* const event_engine_;
+  // Legacy context
+  // TODO(ctiller): remove
+  grpc_call_context_element* legacy_context_;
+  RefCountedPtr<CallArenaAllocator> call_arena_allocator_if_arena_is_owned_;
+  bool legacy_context_is_owned_;
 };
 
 class CallInitiator {
@@ -446,6 +534,15 @@ class CallHandler {
 
   Arena* arena() { return spine_->arena(); }
 
+  grpc_event_engine::experimental::EventEngine* event_engine() {
+    return DownCast<CallSpine*>(spine_.get())->event_engine();
+  }
+
+  // TODO(ctiller): re-evaluate this API
+  grpc_call_context_element* legacy_context() {
+    return DownCast<CallSpine*>(spine_.get())->legacy_context();
+  }
+
  private:
   RefCountedPtr<CallSpineInterface> spine_;
 };
@@ -482,8 +579,19 @@ class UnstartedCallHandler {
     return spine_->party().SpawnWaitable(name, std::move(promise_factory));
   }
 
+  ClientMetadata& UnprocessedClientInitialMetadata() {
+    return spine_->UnprocessedClientInitialMetadata();
+  }
+
   CallHandler V2HackToStartCallWithoutACallFilterStack() {
-    GPR_ASSERT(DownCast<PipeBasedCallSpine*>(spine_.get()) != nullptr);
+    spine_->V2HackToStartCallWithoutACallFilterStack();
+    return CallHandler(std::move(spine_));
+  }
+
+  CallHandler StartCall(RefCountedPtr<CallFilters::Stack> call_filters) {
+    DownCast<CallSpine*>(spine_.get())
+        ->call_filters()
+        .SetStack(std::move(call_filters));
     return CallHandler(std::move(spine_));
   }
 
@@ -498,10 +606,11 @@ struct CallInitiatorAndHandler {
   UnstartedCallHandler handler;
 };
 
-CallInitiatorAndHandler MakeCall(
+CallInitiatorAndHandler MakeCallPair(
     ClientMetadataHandle client_initial_metadata,
     grpc_event_engine::experimental::EventEngine* event_engine, Arena* arena,
-    bool is_arena_owned);
+    RefCountedPtr<CallArenaAllocator> call_arena_allocator_if_arena_is_owned,
+    grpc_call_context_element* legacy_context);
 
 template <typename CallHalf>
 auto OutgoingMessages(CallHalf h) {
diff --git a/src/core/lib/transport/interception_chain.cc b/src/core/lib/transport/interception_chain.cc
new file mode 100644
index 00000000000..4d6ad34e315
--- /dev/null
+++ b/src/core/lib/transport/interception_chain.cc
@@ -0,0 +1,156 @@
+// Copyright 2024 gRPC 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
+//
+//     http://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 "src/core/lib/transport/interception_chain.h"
+
+#include <cstddef>
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/gprpp/match.h"
+#include "src/core/lib/transport/call_destination.h"
+#include "src/core/lib/transport/call_filters.h"
+#include "src/core/lib/transport/call_spine.h"
+#include "src/core/lib/transport/metadata.h"
+
+namespace grpc_core {
+
+std::atomic<size_t> InterceptionChainBuilder::next_filter_id_{0};
+
+///////////////////////////////////////////////////////////////////////////////
+// HijackedCall
+
+CallInitiator HijackedCall::MakeCall() {
+  auto metadata = Arena::MakePooled<ClientMetadata>();
+  *metadata = metadata_->Copy();
+  return MakeCallWithMetadata(std::move(metadata));
+}
+
+CallInitiator HijackedCall::MakeCallWithMetadata(
+    ClientMetadataHandle metadata) {
+  auto call = MakeCallPair(std::move(metadata), call_handler_.event_engine(),
+                           call_handler_.arena(), nullptr,
+                           call_handler_.legacy_context());
+  destination_->StartCall(std::move(call.handler));
+  return std::move(call.initiator);
+}
+
+namespace {
+class CallStarter final : public UnstartedCallDestination {
+ public:
+  CallStarter(RefCountedPtr<CallFilters::Stack> stack,
+              RefCountedPtr<CallDestination> destination)
+      : stack_(std::move(stack)), destination_(std::move(destination)) {}
+
+  void Orphaned() override {
+    stack_.reset();
+    destination_.reset();
+  }
+
+  void StartCall(UnstartedCallHandler unstarted_call_handler) override {
+    destination_->HandleCall(unstarted_call_handler.StartCall(stack_));
+  }
+
+ private:
+  RefCountedPtr<CallFilters::Stack> stack_;
+  RefCountedPtr<CallDestination> destination_;
+};
+
+class TerminalInterceptor final : public UnstartedCallDestination {
+ public:
+  explicit TerminalInterceptor(
+      RefCountedPtr<CallFilters::Stack> stack,
+      RefCountedPtr<UnstartedCallDestination> destination)
+      : stack_(std::move(stack)), destination_(std::move(destination)) {}
+
+  void Orphaned() override {
+    stack_.reset();
+    destination_.reset();
+  }
+
+  void StartCall(UnstartedCallHandler unstarted_call_handler) override {
+    unstarted_call_handler.SpawnGuarded(
+        "start_call",
+        Map(interception_chain_detail::HijackCall(unstarted_call_handler,
+                                                  destination_, stack_),
+            [](ValueOrFailure<HijackedCall> hijacked_call) -> StatusFlag {
+              if (!hijacked_call.ok()) return Failure{};
+              ForwardCall(hijacked_call.value().original_call_handler(),
+                          hijacked_call.value().MakeLastCall());
+              return Success{};
+            }));
+  }
+
+ private:
+  RefCountedPtr<CallFilters::Stack> stack_;
+  RefCountedPtr<UnstartedCallDestination> destination_;
+};
+}  // namespace
+
+///////////////////////////////////////////////////////////////////////////////
+// InterceptionChain::Builder
+
+void InterceptionChainBuilder::AddInterceptor(
+    absl::StatusOr<RefCountedPtr<Interceptor>> interceptor) {
+  if (!status_.ok()) return;
+  if (!interceptor.ok()) {
+    status_ = interceptor.status();
+    return;
+  }
+  (*interceptor)->filter_stack_ = MakeFilterStack();
+  if (top_interceptor_ == nullptr) {
+    top_interceptor_ = std::move(*interceptor);
+  } else {
+    Interceptor* previous = top_interceptor_.get();
+    while (previous->wrapped_destination_ != nullptr) {
+      previous = DownCast<Interceptor*>(previous->wrapped_destination_.get());
+    }
+    previous->wrapped_destination_ = std::move(*interceptor);
+  }
+}
+
+absl::StatusOr<RefCountedPtr<UnstartedCallDestination>>
+InterceptionChainBuilder::Build(FinalDestination final_destination) {
+  if (!status_.ok()) return status_;
+  // Build the final UnstartedCallDestination in the chain - what we do here
+  // depends on both the type of the final destination and the filters we have
+  // that haven't been captured into an Interceptor yet.
+  RefCountedPtr<UnstartedCallDestination> terminator = Match(
+      final_destination,
+      [this](RefCountedPtr<UnstartedCallDestination> final_destination)
+          -> RefCountedPtr<UnstartedCallDestination> {
+        if (stack_builder_.has_value()) {
+          return MakeRefCounted<TerminalInterceptor>(MakeFilterStack(),
+                                                     final_destination);
+        }
+        return final_destination;
+      },
+      [this](RefCountedPtr<CallDestination> final_destination)
+          -> RefCountedPtr<UnstartedCallDestination> {
+        return MakeRefCounted<CallStarter>(MakeFilterStack(),
+                                           std::move(final_destination));
+      });
+  // Now append the terminator to the interceptor chain.
+  if (top_interceptor_ == nullptr) {
+    return std::move(terminator);
+  }
+  Interceptor* previous = top_interceptor_.get();
+  while (previous->wrapped_destination_ != nullptr) {
+    previous = DownCast<Interceptor*>(previous->wrapped_destination_.get());
+  }
+  previous->wrapped_destination_ = std::move(terminator);
+  return std::move(top_interceptor_);
+}
+
+}  // namespace grpc_core
diff --git a/src/core/lib/transport/interception_chain.h b/src/core/lib/transport/interception_chain.h
new file mode 100644
index 00000000000..5b05e481ff6
--- /dev/null
+++ b/src/core/lib/transport/interception_chain.h
@@ -0,0 +1,225 @@
+// Copyright 2024 gRPC 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
+//
+//     http://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 GRPC_SRC_CORE_LIB_TRANSPORT_INTERCEPTION_CHAIN_H
+#define GRPC_SRC_CORE_LIB_TRANSPORT_INTERCEPTION_CHAIN_H
+
+#include <memory>
+#include <vector>
+
+#include <grpc/support/port_platform.h>
+
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/transport/call_destination.h"
+#include "src/core/lib/transport/call_filters.h"
+#include "src/core/lib/transport/call_spine.h"
+#include "src/core/lib/transport/metadata.h"
+
+namespace grpc_core {
+
+class InterceptionChainBuilder;
+
+// One hijacked call. Using this we can get access to the CallHandler for the
+// call object above us, the processed metadata from any filters/interceptors
+// above us, and also create new CallInterceptor objects that will be handled
+// below.
+class HijackedCall final {
+ public:
+  HijackedCall(ClientMetadataHandle metadata,
+               RefCountedPtr<UnstartedCallDestination> destination,
+               CallHandler call_handler)
+      : metadata_(std::move(metadata)),
+        destination_(std::move(destination)),
+        call_handler_(std::move(call_handler)) {}
+
+  // Create a new call and pass it down the stack.
+  // This can be called as many times as needed.
+  CallInitiator MakeCall();
+  // Per MakeCall(), but precludes creating further calls.
+  // Allows us to optimize by not copying initial metadata.
+  CallInitiator MakeLastCall() {
+    return MakeCallWithMetadata(std::move(metadata_));
+  }
+
+  CallHandler& original_call_handler() { return call_handler_; }
+
+  ClientMetadata& client_metadata() { return *metadata_; }
+
+ private:
+  CallInitiator MakeCallWithMetadata(ClientMetadataHandle metadata);
+
+  ClientMetadataHandle metadata_;
+  RefCountedPtr<UnstartedCallDestination> destination_;
+  CallHandler call_handler_;
+};
+
+namespace interception_chain_detail {
+
+inline auto HijackCall(UnstartedCallHandler unstarted_call_handler,
+                       RefCountedPtr<UnstartedCallDestination> destination,
+                       RefCountedPtr<CallFilters::Stack> stack) {
+  auto call_handler = unstarted_call_handler.StartCall(stack);
+  return Map(
+      call_handler.PullClientInitialMetadata(),
+      [call_handler,
+       destination](ValueOrFailure<ClientMetadataHandle> metadata) mutable
+      -> ValueOrFailure<HijackedCall> {
+        if (!metadata.ok()) return Failure{};
+        return HijackedCall(std::move(metadata.value()), std::move(destination),
+                            std::move(call_handler));
+      });
+}
+
+}  // namespace interception_chain_detail
+
+// A delegating UnstartedCallDestination for use as a hijacking filter.
+// Implementations may look at the unprocessed initial metadata
+// and decide to do one of two things:
+//
+// 1. It can hijack the call. Returns a HijackedCall object that can
+//    be used to start new calls with the same metadata.
+//
+// 2. It can consume the call by calling `Consume`.
+//
+// Upon the StartCall call the UnstartedCallHandler will be from the last
+// *Interceptor* in the call chain (without having been processed by any
+// intervening filters) -- note that this is commonly not useful (not enough
+// guarantees), and so it's usually better to Hijack and examine the metadata.
+class Interceptor : public UnstartedCallDestination {
+ protected:
+  // Returns a promise that resolves to a HijackedCall instance.
+  // Hijacking is the process of taking over a call and starting one or more new
+  // ones.
+  auto Hijack(UnstartedCallHandler unstarted_call_handler) {
+    return interception_chain_detail::HijackCall(
+        std::move(unstarted_call_handler), wrapped_destination_, filter_stack_);
+  }
+
+  // Consume this call - it will not be passed on to any further filters.
+  CallHandler Consume(UnstartedCallHandler unstarted_call_handler) {
+    return unstarted_call_handler.StartCall(filter_stack_);
+  }
+
+  // TODO(ctiller): Consider a Passthrough() method that allows the call to be
+  // passed on to the next filter in the chain without any interception by the
+  // current filter.
+
+ private:
+  friend class InterceptionChainBuilder;
+
+  RefCountedPtr<UnstartedCallDestination> wrapped_destination_;
+  RefCountedPtr<CallFilters::Stack> filter_stack_;
+};
+
+class InterceptionChainBuilder final {
+ public:
+  // The kind of destination that the chain will eventually call.
+  // We can bottom out in various types depending on where we're intercepting:
+  // - The top half of the client channel wants to terminate on a
+  //   UnstartedCallDestination (specifically the LB call destination).
+  // - The bottom half of the client channel and the server code wants to
+  //   terminate on a ClientTransport - which unlike a
+  //   UnstartedCallDestination demands a started CallHandler.
+  // There's some adaption code that's needed to start filters just prior
+  // to the bottoming out, and some design considerations to make with that.
+  // One way (that's not chosen here) would be to have the caller of the
+  // Builder provide something that can build an adaptor
+  // UnstartedCallDestination with parameters supplied by this builder - that
+  // disperses the responsibility of building the adaptor to the caller, which
+  // is not ideal - we might want to adjust the way this construct is built in
+  // the future, and building is a builder responsibility.
+  // Instead, we declare a relatively closed set of destinations here, and
+  // hide the adaptors inside the builder at build time.
+  using FinalDestination =
+      absl::variant<RefCountedPtr<UnstartedCallDestination>,
+                    RefCountedPtr<CallDestination>>;
+
+  explicit InterceptionChainBuilder(ChannelArgs args)
+      : args_(std::move(args)) {}
+
+  // Add a filter with a `Call` class as an inner member.
+  // Call class must be one compatible with the filters described in
+  // call_filters.h.
+  template <typename T>
+  absl::enable_if_t<sizeof(typename T::Call) != 0, InterceptionChainBuilder&>
+  Add() {
+    if (!status_.ok()) return *this;
+    auto filter = T::Create(args_, {FilterInstanceId(FilterTypeId<T>())});
+    if (!filter.ok()) {
+      status_ = filter.status();
+      return *this;
+    }
+    auto& sb = stack_builder();
+    sb.Add(filter.value().get());
+    sb.AddOwnedObject(std::move(filter.value()));
+    return *this;
+  };
+
+  // Add a filter that is an interceptor - one that can hijack calls.
+  template <typename T>
+  absl::enable_if_t<std::is_base_of<Interceptor, T>::value,
+                    InterceptionChainBuilder&>
+  Add() {
+    AddInterceptor(T::Create(args_, {FilterInstanceId(FilterTypeId<T>())}));
+    return *this;
+  };
+
+  // Add a filter that just mutates server trailing metadata.
+  template <typename F>
+  void AddOnServerTrailingMetadata(F f) {
+    stack_builder().AddOnServerTrailingMetadata(std::move(f));
+  }
+
+  // Build this stack
+  absl::StatusOr<RefCountedPtr<UnstartedCallDestination>> Build(
+      FinalDestination final_destination);
+
+  const ChannelArgs& channel_args() const { return args_; }
+
+ private:
+  CallFilters::StackBuilder& stack_builder() {
+    if (!stack_builder_.has_value()) stack_builder_.emplace();
+    return *stack_builder_;
+  }
+
+  RefCountedPtr<CallFilters::Stack> MakeFilterStack() {
+    auto stack = stack_builder().Build();
+    stack_builder_.reset();
+    return stack;
+  }
+
+  template <typename T>
+  static size_t FilterTypeId() {
+    static const size_t id =
+        next_filter_id_.fetch_add(1, std::memory_order_relaxed);
+    return id;
+  }
+
+  size_t FilterInstanceId(size_t filter_type) {
+    return filter_type_counts_[filter_type]++;
+  }
+
+  void AddInterceptor(absl::StatusOr<RefCountedPtr<Interceptor>> interceptor);
+
+  ChannelArgs args_;
+  absl::optional<CallFilters::StackBuilder> stack_builder_;
+  RefCountedPtr<Interceptor> top_interceptor_;
+  absl::Status status_;
+  std::map<size_t, size_t> filter_type_counts_;
+  static std::atomic<size_t> next_filter_id_;
+};
+
+}  // namespace grpc_core
+
+#endif  // GRPC_SRC_CORE_LIB_TRANSPORT_INTERCEPTION_CHAIN_H
diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py
index fc65b906b34..b8848c863d1 100644
--- a/src/python/grpcio/grpc_core_dependencies.py
+++ b/src/python/grpcio/grpc_core_dependencies.py
@@ -755,9 +755,9 @@ CORE_SOURCE_FILES = [
     'src/core/lib/surface/wait_for_cq_end_op.cc',
     'src/core/lib/transport/batch_builder.cc',
     'src/core/lib/transport/bdp_estimator.cc',
+    'src/core/lib/transport/call_arena_allocator.cc',
     'src/core/lib/transport/call_filters.cc',
     'src/core/lib/transport/call_final_info.cc',
-    'src/core/lib/transport/call_size_estimator.cc',
     'src/core/lib/transport/call_spine.cc',
     'src/core/lib/transport/connectivity_state.cc',
     'src/core/lib/transport/endpoint_info_handshaker.cc',
diff --git a/test/core/promise/BUILD b/test/core/promise/BUILD
index 5bd4ddea346..ac99d1a9fcd 100644
--- a/test/core/promise/BUILD
+++ b/test/core/promise/BUILD
@@ -19,6 +19,15 @@ licenses(["notice"])
 
 grpc_package(name = "test/core/promise")
 
+grpc_cc_library(
+    name = "poll_matcher",
+    testonly = True,
+    hdrs = ["poll_matcher.h"],
+    external_deps = ["gtest"],
+    visibility = ["//test/core:__subpackages__"],
+    deps = ["//src/core:poll"],
+)
+
 grpc_cc_library(
     name = "test_wakeup_schedulers",
     testonly = True,
@@ -496,6 +505,7 @@ grpc_cc_test(
     uses_event_engine = False,
     uses_polling = False,
     deps = [
+        "poll_matcher",
         "//src/core:loop",
         "//src/core:map",
         "//src/core:notification",
diff --git a/test/core/promise/observable_test.cc b/test/core/promise/observable_test.cc
index 48f52b4978c..e3c74332f04 100644
--- a/test/core/promise/observable_test.cc
+++ b/test/core/promise/observable_test.cc
@@ -26,6 +26,7 @@
 #include "src/core/lib/gprpp/notification.h"
 #include "src/core/lib/promise/loop.h"
 #include "src/core/lib/promise/map.h"
+#include "test/core/promise/poll_matcher.h"
 
 using testing::Mock;
 using testing::StrictMock;
@@ -58,34 +59,6 @@ class MockActivity : public Activity, public Wakeable {
   std::unique_ptr<ScopedActivity> scoped_activity_;
 };
 
-MATCHER(IsPending, "") {
-  if (arg.ready()) {
-    *result_listener << "is ready";
-    return false;
-  }
-  return true;
-}
-
-MATCHER(IsReady, "") {
-  if (arg.pending()) {
-    *result_listener << "is pending";
-    return false;
-  }
-  return true;
-}
-
-MATCHER_P(IsReady, value, "") {
-  if (arg.pending()) {
-    *result_listener << "is pending";
-    return false;
-  }
-  if (arg.value() != value) {
-    *result_listener << "is " << ::testing::PrintToString(arg.value());
-    return false;
-  }
-  return true;
-}
-
 TEST(ObservableTest, ImmediateNext) {
   Observable<int> observable(1);
   auto next = observable.Next(0);
diff --git a/test/core/promise/poll_matcher.h b/test/core/promise/poll_matcher.h
new file mode 100644
index 00000000000..1c571effbcb
--- /dev/null
+++ b/test/core/promise/poll_matcher.h
@@ -0,0 +1,60 @@
+// Copyright 2024 gRPC 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
+//
+//     http://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 GRPC_TEST_CORE_PROMISE_POLL_MATCHER_H
+#define GRPC_TEST_CORE_PROMISE_POLL_MATCHER_H
+
+#include "gmock/gmock.h"
+
+// Various gmock matchers for Poll
+
+namespace grpc_core {
+
+// Expect that a promise is still pending:
+// EXPECT_THAT(some_promise(), IsPending());
+MATCHER(IsPending, "") {
+  if (arg.ready()) {
+    *result_listener << "is ready";
+    return false;
+  }
+  return true;
+}
+
+// Expect that a promise is ready:
+// EXPECT_THAT(some_promise(), IsReady());
+MATCHER(IsReady, "") {
+  if (arg.pending()) {
+    *result_listener << "is pending";
+    return false;
+  }
+  return true;
+}
+
+// Expect that a promise is ready with a specific value:
+// EXPECT_THAT(some_promise(), IsReady(value));
+MATCHER_P(IsReady, value, "") {
+  if (arg.pending()) {
+    *result_listener << "is pending";
+    return false;
+  }
+  if (arg.value() != value) {
+    *result_listener << "is " << ::testing::PrintToString(arg.value());
+    return false;
+  }
+  return true;
+}
+
+}  // namespace grpc_core
+
+#endif  // GRPC_TEST_CORE_PROMISE_POLL_MATCHER_H
diff --git a/test/core/transport/BUILD b/test/core/transport/BUILD
index 516e23e2f20..519f3c3bc38 100644
--- a/test/core/transport/BUILD
+++ b/test/core/transport/BUILD
@@ -35,6 +35,23 @@ grpc_cc_test(
     ],
 )
 
+grpc_cc_test(
+    name = "interception_chain_test",
+    srcs = ["interception_chain_test.cc"],
+    external_deps = [
+        "gtest",
+    ],
+    language = "C++",
+    uses_event_engine = False,
+    uses_polling = False,
+    deps = [
+        "//:grpc_base",
+        "//src/core:interception_chain",
+        "//src/core:resource_quota",
+        "//test/core/promise:poll_matcher",
+    ],
+)
+
 grpc_cc_test(
     name = "call_filters_test",
     srcs = ["call_filters_test.cc"],
@@ -46,6 +63,7 @@ grpc_cc_test(
     uses_polling = False,
     deps = [
         "//src/core:call_filters",
+        "//test/core/promise:poll_matcher",
     ],
 )
 
diff --git a/test/core/transport/call_filters_test.cc b/test/core/transport/call_filters_test.cc
index a2431a909f8..8044aa85610 100644
--- a/test/core/transport/call_filters_test.cc
+++ b/test/core/transport/call_filters_test.cc
@@ -19,6 +19,8 @@
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
+#include "test/core/promise/poll_matcher.h"
+
 using testing::Mock;
 using testing::StrictMock;
 
@@ -57,34 +59,6 @@ class MockActivity : public Activity, public Wakeable {
   std::unique_ptr<ScopedActivity> scoped_activity_;
 };
 
-MATCHER(IsPending, "") {
-  if (arg.ready()) {
-    *result_listener << "is ready";
-    return false;
-  }
-  return true;
-}
-
-MATCHER(IsReady, "") {
-  if (arg.pending()) {
-    *result_listener << "is pending";
-    return false;
-  }
-  return true;
-}
-
-MATCHER_P(IsReady, value, "") {
-  if (arg.pending()) {
-    *result_listener << "is pending";
-    return false;
-  }
-  if (arg.value() != value) {
-    *result_listener << "is " << ::testing::PrintToString(arg.value());
-    return false;
-  }
-  return true;
-}
-
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/test/core/transport/chaotic_good/client_transport_error_test.cc b/test/core/transport/chaotic_good/client_transport_error_test.cc
index bd1e1b77f7a..737f71a7aa2 100644
--- a/test/core/transport/chaotic_good/client_transport_error_test.cc
+++ b/test/core/transport/chaotic_good/client_transport_error_test.cc
@@ -105,16 +105,19 @@ struct MockPromiseEndpoint {
 auto SendClientToServerMessages(CallInitiator initiator, int num_messages) {
   return Loop([initiator, num_messages]() mutable {
     bool has_message = (num_messages > 0);
-    return If(has_message,
-              Seq(initiator.PushMessage(Arena::MakePooled<Message>()),
-                  [&num_messages]() -> LoopCtl<absl::Status> {
-                    --num_messages;
-                    return Continue();
-                  }),
-              [initiator]() mutable -> LoopCtl<absl::Status> {
-                initiator.FinishSends();
-                return absl::OkStatus();
-              });
+    return If(
+        has_message,
+        [initiator, &num_messages]() mutable {
+          return Seq(initiator.PushMessage(Arena::MakePooled<Message>()),
+                     [&num_messages]() -> LoopCtl<absl::Status> {
+                       --num_messages;
+                       return Continue();
+                     });
+        },
+        [initiator]() mutable -> LoopCtl<absl::Status> {
+          initiator.FinishSends();
+          return absl::OkStatus();
+        });
   });
 }
 
@@ -130,7 +133,6 @@ class ClientTransportTest : public ::testing::Test {
   event_engine() {
     return event_engine_;
   }
-  MemoryAllocator* memory_allocator() { return &allocator_; }
 
   ChannelArgs MakeChannelArgs() {
     return CoreConfiguration::Get()
@@ -138,6 +140,12 @@ class ClientTransportTest : public ::testing::Test {
         .PreconditionChannelArgs(nullptr);
   }
 
+  auto MakeCall(ClientMetadataHandle client_initial_metadata) {
+    auto* arena = call_arena_allocator_->MakeArena();
+    return MakeCallPair(std::move(client_initial_metadata), event_engine_.get(),
+                        arena, call_arena_allocator_, nullptr);
+  }
+
  private:
   std::shared_ptr<grpc_event_engine::experimental::FuzzingEventEngine>
       event_engine_{
@@ -149,9 +157,12 @@ class ClientTransportTest : public ::testing::Test {
                 return options;
               }(),
               fuzzing_event_engine::Actions())};
-  MemoryAllocator allocator_ = MakeResourceQuota("test-quota")
-                                   ->memory_quota()
-                                   ->CreateMemoryAllocator("test-allocator");
+  RefCountedPtr<CallArenaAllocator> call_arena_allocator_{
+      MakeRefCounted<CallArenaAllocator>(
+          MakeResourceQuota("test-quota")
+              ->memory_quota()
+              ->CreateMemoryAllocator("test-allocator"),
+          1024)};
 };
 
 TEST_F(ClientTransportTest, AddOneStreamWithWriteFailed) {
@@ -177,8 +188,7 @@ TEST_F(ClientTransportTest, AddOneStreamWithWriteFailed) {
       std::move(control_endpoint.promise_endpoint),
       std::move(data_endpoint.promise_endpoint), MakeChannelArgs(),
       event_engine(), HPackParser(), HPackCompressor());
-  auto call = MakeCall(TestInitialMetadata(), event_engine().get(),
-                       Arena::Create(8192, memory_allocator()), true);
+  auto call = MakeCall(TestInitialMetadata());
   transport->StartCall(call.handler.V2HackToStartCallWithoutACallFilterStack());
   call.initiator.SpawnGuarded("test-send",
                               [initiator = call.initiator]() mutable {
@@ -222,8 +232,7 @@ TEST_F(ClientTransportTest, AddOneStreamWithReadFailed) {
       std::move(control_endpoint.promise_endpoint),
       std::move(data_endpoint.promise_endpoint), MakeChannelArgs(),
       event_engine(), HPackParser(), HPackCompressor());
-  auto call = MakeCall(TestInitialMetadata(), event_engine().get(),
-                       Arena::Create(8192, memory_allocator()), true);
+  auto call = MakeCall(TestInitialMetadata());
   transport->StartCall(call.handler.V2HackToStartCallWithoutACallFilterStack());
   call.initiator.SpawnGuarded("test-send",
                               [initiator = call.initiator]() mutable {
@@ -275,12 +284,10 @@ TEST_F(ClientTransportTest, AddMultipleStreamWithWriteFailed) {
       std::move(control_endpoint.promise_endpoint),
       std::move(data_endpoint.promise_endpoint), MakeChannelArgs(),
       event_engine(), HPackParser(), HPackCompressor());
-  auto call1 = MakeCall(TestInitialMetadata(), event_engine().get(),
-                        Arena::Create(8192, memory_allocator()), true);
+  auto call1 = MakeCall(TestInitialMetadata());
   transport->StartCall(
       call1.handler.V2HackToStartCallWithoutACallFilterStack());
-  auto call2 = MakeCall(TestInitialMetadata(), event_engine().get(),
-                        Arena::Create(8192, memory_allocator()), true);
+  auto call2 = MakeCall(TestInitialMetadata());
   transport->StartCall(
       call2.handler.V2HackToStartCallWithoutACallFilterStack());
   call1.initiator.SpawnGuarded(
@@ -347,12 +354,10 @@ TEST_F(ClientTransportTest, AddMultipleStreamWithReadFailed) {
       std::move(control_endpoint.promise_endpoint),
       std::move(data_endpoint.promise_endpoint), MakeChannelArgs(),
       event_engine(), HPackParser(), HPackCompressor());
-  auto call1 = MakeCall(TestInitialMetadata(), event_engine().get(),
-                        Arena::Create(8192, memory_allocator()), true);
+  auto call1 = MakeCall(TestInitialMetadata());
   transport->StartCall(
       call1.handler.V2HackToStartCallWithoutACallFilterStack());
-  auto call2 = MakeCall(TestInitialMetadata(), event_engine().get(),
-                        Arena::Create(8192, memory_allocator()), true);
+  auto call2 = MakeCall(TestInitialMetadata());
   transport->StartCall(
       call2.handler.V2HackToStartCallWithoutACallFilterStack());
   call1.initiator.SpawnGuarded(
diff --git a/test/core/transport/chaotic_good/client_transport_test.cc b/test/core/transport/chaotic_good/client_transport_test.cc
index 3acd0c0c273..b5dc5f823f3 100644
--- a/test/core/transport/chaotic_good/client_transport_test.cc
+++ b/test/core/transport/chaotic_good/client_transport_test.cc
@@ -15,6 +15,7 @@
 #include "src/core/ext/transport/chaotic_good/client_transport.h"
 
 #include <algorithm>
+#include <cstddef>
 #include <cstdlib>
 #include <initializer_list>
 #include <memory>
@@ -78,12 +79,15 @@ auto SendClientToServerMessages(CallInitiator initiator, int num_messages) {
     bool has_message = (i < num_messages);
     return If(
         has_message,
-        Seq(initiator.PushMessage(Arena::MakePooled<Message>(
-                SliceBuffer(Slice::FromCopiedString(std::to_string(i))), 0)),
-            [&i]() -> LoopCtl<absl::Status> {
-              ++i;
-              return Continue();
-            }),
+        [initiator, &i]() mutable {
+          return Seq(
+              initiator.PushMessage(Arena::MakePooled<Message>(
+                  SliceBuffer(Slice::FromCopiedString(std::to_string(i))), 0)),
+              [&i]() -> LoopCtl<absl::Status> {
+                ++i;
+                return Continue();
+              });
+        },
         [initiator]() mutable -> LoopCtl<absl::Status> {
           initiator.FinishSends();
           return absl::OkStatus();
@@ -115,8 +119,7 @@ TEST_F(TransportTest, AddOneStream) {
       std::move(control_endpoint.promise_endpoint),
       std::move(data_endpoint.promise_endpoint), MakeChannelArgs(),
       event_engine(), HPackParser(), HPackCompressor());
-  auto call = MakeCall(TestInitialMetadata(), event_engine().get(),
-                       Arena::Create(1024, memory_allocator()), true);
+  auto call = MakeCall(TestInitialMetadata());
   transport->StartCall(call.handler.V2HackToStartCallWithoutACallFilterStack());
   StrictMock<MockFunction<void()>> on_done;
   EXPECT_CALL(on_done, Call());
@@ -202,8 +205,7 @@ TEST_F(TransportTest, AddOneStreamMultipleMessages) {
       std::move(control_endpoint.promise_endpoint),
       std::move(data_endpoint.promise_endpoint), MakeChannelArgs(),
       event_engine(), HPackParser(), HPackCompressor());
-  auto call = MakeCall(TestInitialMetadata(), event_engine().get(),
-                       Arena::Create(8192, memory_allocator()), true);
+  auto call = MakeCall(TestInitialMetadata());
   transport->StartCall(call.handler.V2HackToStartCallWithoutACallFilterStack());
   StrictMock<MockFunction<void()>> on_done;
   EXPECT_CALL(on_done, Call());
diff --git a/test/core/transport/chaotic_good/server_transport_test.cc b/test/core/transport/chaotic_good/server_transport_test.cc
index a4e0272b87c..a5dd0008b9a 100644
--- a/test/core/transport/chaotic_good/server_transport_test.cc
+++ b/test/core/transport/chaotic_good/server_transport_test.cc
@@ -112,7 +112,7 @@ TEST_F(TransportTest, ReadAndWriteOneMessage) {
   data_endpoint.ExpectRead(
       {EventEngineSlice::FromCopiedString("12345678"), Zeros(56)}, nullptr);
   // Once that's read we'll create a new call
-  auto* call_arena = Arena::Create(1024, memory_allocator());
+  auto* call_arena = MakeArena();
   EXPECT_CALL(acceptor, CreateArena).WillOnce(Return(call_arena));
   StrictMock<MockFunction<void()>> on_done;
   EXPECT_CALL(acceptor, CreateCall(_, call_arena))
@@ -121,9 +121,9 @@ TEST_F(TransportTest, ReadAndWriteOneMessage) {
         EXPECT_EQ(client_initial_metadata->get_pointer(HttpPathMetadata())
                       ->as_string_view(),
                   "/demo.Service/Step");
-        CallInitiatorAndHandler call =
-            MakeCall(std::move(client_initial_metadata), event_engine().get(),
-                     call_arena, true);
+        CallInitiatorAndHandler call = MakeCallPair(
+            std::move(client_initial_metadata), event_engine().get(),
+            call_arena, call_arena_allocator(), nullptr);
         auto handler = call.handler.V2HackToStartCallWithoutACallFilterStack();
         handler.SpawnInfallible("test-io", [&on_done, handler]() mutable {
           return Seq(
diff --git a/test/core/transport/chaotic_good/transport_test.h b/test/core/transport/chaotic_good/transport_test.h
index e70158bb8cf..3604be1f190 100644
--- a/test/core/transport/chaotic_good/transport_test.h
+++ b/test/core/transport/chaotic_good/transport_test.h
@@ -36,7 +36,17 @@ class TransportTest : public ::testing::Test {
     return event_engine_;
   }
 
-  MemoryAllocator* memory_allocator() { return &allocator_; }
+  Arena* MakeArena() { return call_arena_allocator_->MakeArena(); }
+
+  RefCountedPtr<CallArenaAllocator> call_arena_allocator() {
+    return call_arena_allocator_;
+  }
+
+  auto MakeCall(ClientMetadataHandle client_initial_metadata) {
+    auto* arena = call_arena_allocator_->MakeArena();
+    return MakeCallPair(std::move(client_initial_metadata), event_engine_.get(),
+                        arena, call_arena_allocator_, nullptr);
+  }
 
  private:
   std::shared_ptr<grpc_event_engine::experimental::FuzzingEventEngine>
@@ -49,9 +59,12 @@ class TransportTest : public ::testing::Test {
                 return options;
               }(),
               fuzzing_event_engine::Actions())};
-  MemoryAllocator allocator_ = MakeResourceQuota("test-quota")
-                                   ->memory_quota()
-                                   ->CreateMemoryAllocator("test-allocator");
+  RefCountedPtr<CallArenaAllocator> call_arena_allocator_{
+      MakeRefCounted<CallArenaAllocator>(
+          MakeResourceQuota("test-quota")
+              ->memory_quota()
+              ->CreateMemoryAllocator("test-allocator"),
+          1024)};
 };
 
 grpc_event_engine::experimental::Slice SerializedFrameHeader(
diff --git a/test/core/transport/interception_chain_test.cc b/test/core/transport/interception_chain_test.cc
new file mode 100644
index 00000000000..f72fd59e019
--- /dev/null
+++ b/test/core/transport/interception_chain_test.cc
@@ -0,0 +1,406 @@
+// Copyright 2024 gRPC 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
+//
+//     http://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 "src/core/lib/transport/interception_chain.h"
+
+#include <memory>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include <grpc/support/log.h>
+
+#include "src/core/lib/channel/promise_based_filter.h"
+#include "src/core/lib/resource_quota/resource_quota.h"
+#include "test/core/promise/poll_matcher.h"
+
+namespace grpc_core {
+namespace {
+
+///////////////////////////////////////////////////////////////////////////////
+// Mutate metadata by annotating that it passed through a filter "x"
+
+void AnnotatePassedThrough(ClientMetadata& md, int x) {
+  md.Append(absl::StrCat("passed-through-", x), Slice::FromCopiedString("true"),
+            [](absl::string_view, const Slice&) { Crash("unreachable"); });
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// CreationLog helps us reason about filter creation order by logging a small
+// record of each filter's creation.
+
+struct CreationLogEntry {
+  size_t filter_instance_id;
+  size_t type_tag;
+
+  bool operator==(const CreationLogEntry& other) const {
+    return filter_instance_id == other.filter_instance_id &&
+           type_tag == other.type_tag;
+  }
+
+  friend std::ostream& operator<<(std::ostream& os,
+                                  const CreationLogEntry& entry) {
+    return os << "{filter_instance_id=" << entry.filter_instance_id
+              << ", type_tag=" << entry.type_tag << "}";
+  }
+};
+
+struct CreationLog {
+  struct RawPointerChannelArgTag {};
+  static absl::string_view ChannelArgName() { return "creation_log"; }
+  std::vector<CreationLogEntry> entries;
+};
+
+void MaybeLogCreation(const ChannelArgs& channel_args,
+                      ChannelFilter::Args filter_args, size_t type_tag) {
+  auto* log = channel_args.GetPointer<CreationLog>("creation_log");
+  if (log == nullptr) return;
+  log->entries.push_back(CreationLogEntry{filter_args.instance_id(), type_tag});
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Test call filter
+
+template <int I>
+class TestFilter {
+ public:
+  class Call {
+   public:
+    void OnClientInitialMetadata(ClientMetadata& md) {
+      AnnotatePassedThrough(md, I);
+    }
+    static const NoInterceptor OnServerInitialMetadata;
+    static const NoInterceptor OnClientToServerMessage;
+    static const NoInterceptor OnServerToClientMessage;
+    static const NoInterceptor OnServerTrailingMetadata;
+    static const NoInterceptor OnFinalize;
+  };
+
+  static absl::StatusOr<std::unique_ptr<TestFilter<I>>> Create(
+      const ChannelArgs& channel_args, ChannelFilter::Args filter_args) {
+    MaybeLogCreation(channel_args, filter_args, I);
+    return std::make_unique<TestFilter<I>>();
+  }
+
+ private:
+  std::unique_ptr<int> i_ = std::make_unique<int>(I);
+};
+
+template <int I>
+const NoInterceptor TestFilter<I>::Call::OnServerInitialMetadata;
+template <int I>
+const NoInterceptor TestFilter<I>::Call::OnClientToServerMessage;
+template <int I>
+const NoInterceptor TestFilter<I>::Call::OnServerToClientMessage;
+template <int I>
+const NoInterceptor TestFilter<I>::Call::OnServerTrailingMetadata;
+template <int I>
+const NoInterceptor TestFilter<I>::Call::OnFinalize;
+
+///////////////////////////////////////////////////////////////////////////////
+// Test call filter that fails to instantiate
+
+template <int I>
+class FailsToInstantiateFilter {
+ public:
+  class Call {
+   public:
+    static const NoInterceptor OnClientInitialMetadata;
+    static const NoInterceptor OnServerInitialMetadata;
+    static const NoInterceptor OnClientToServerMessage;
+    static const NoInterceptor OnServerToClientMessage;
+    static const NoInterceptor OnServerTrailingMetadata;
+    static const NoInterceptor OnFinalize;
+  };
+
+  static absl::StatusOr<std::unique_ptr<FailsToInstantiateFilter<I>>> Create(
+      const ChannelArgs& channel_args, ChannelFilter::Args filter_args) {
+    MaybeLogCreation(channel_args, filter_args, I);
+    return absl::InternalError(absl::StrCat("👊 failed to instantiate ", I));
+  }
+};
+
+template <int I>
+const NoInterceptor FailsToInstantiateFilter<I>::Call::OnClientInitialMetadata;
+template <int I>
+const NoInterceptor FailsToInstantiateFilter<I>::Call::OnServerInitialMetadata;
+template <int I>
+const NoInterceptor FailsToInstantiateFilter<I>::Call::OnClientToServerMessage;
+template <int I>
+const NoInterceptor FailsToInstantiateFilter<I>::Call::OnServerToClientMessage;
+template <int I>
+const NoInterceptor FailsToInstantiateFilter<I>::Call::OnServerTrailingMetadata;
+template <int I>
+const NoInterceptor FailsToInstantiateFilter<I>::Call::OnFinalize;
+
+///////////////////////////////////////////////////////////////////////////////
+// Test call interceptor - consumes calls
+
+template <int I>
+class TestConsumingInterceptor final : public Interceptor {
+ public:
+  void StartCall(UnstartedCallHandler unstarted_call_handler) override {
+    Consume(std::move(unstarted_call_handler))
+        .PushServerTrailingMetadata(
+            ServerMetadataFromStatus(absl::InternalError("👊 consumed")));
+  }
+  void Orphaned() override {}
+  static absl::StatusOr<RefCountedPtr<TestConsumingInterceptor<I>>> Create(
+      const ChannelArgs& channel_args, ChannelFilter::Args filter_args) {
+    MaybeLogCreation(channel_args, filter_args, I);
+    return MakeRefCounted<TestConsumingInterceptor<I>>();
+  }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Test call interceptor - fails to instantiate
+
+template <int I>
+class TestFailingInterceptor final : public Interceptor {
+ public:
+  void StartCall(UnstartedCallHandler unstarted_call_handler) override {
+    Crash("unreachable");
+  }
+  void Orphaned() override {}
+  static absl::StatusOr<RefCountedPtr<TestFailingInterceptor<I>>> Create(
+      const ChannelArgs& channel_args, ChannelFilter::Args filter_args) {
+    MaybeLogCreation(channel_args, filter_args, I);
+    return absl::InternalError(absl::StrCat("👊 failed to instantiate ", I));
+  }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Test call interceptor - hijacks calls
+
+template <int I>
+class TestHijackingInterceptor final : public Interceptor {
+ public:
+  void StartCall(UnstartedCallHandler unstarted_call_handler) override {
+    unstarted_call_handler.SpawnInfallible(
+        "hijack", [this, unstarted_call_handler]() mutable {
+          return Map(Hijack(std::move(unstarted_call_handler)),
+                     [](ValueOrFailure<HijackedCall> hijacked_call) {
+                       ForwardCall(
+                           hijacked_call.value().original_call_handler(),
+                           hijacked_call.value().MakeCall());
+                       return Empty{};
+                     });
+        });
+  }
+  void Orphaned() override {}
+  static absl::StatusOr<RefCountedPtr<TestHijackingInterceptor<I>>> Create(
+      const ChannelArgs& channel_args, ChannelFilter::Args filter_args) {
+    MaybeLogCreation(channel_args, filter_args, I);
+    return MakeRefCounted<TestHijackingInterceptor<I>>();
+  }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Test fixture
+
+class InterceptionChainTest : public ::testing::Test {
+ protected:
+  InterceptionChainTest() {}
+  ~InterceptionChainTest() override {}
+
+  RefCountedPtr<UnstartedCallDestination> destination() { return destination_; }
+
+  struct FinishedCall {
+    CallInitiator call;
+    ClientMetadataHandle client_metadata;
+    ServerMetadataHandle server_metadata;
+  };
+
+  // Run a call through a UnstartedCallDestination until it's complete.
+  FinishedCall RunCall(UnstartedCallDestination* destination) {
+    auto* arena = call_arena_allocator_->MakeArena();
+    auto call = MakeCallPair(Arena::MakePooled<ClientMetadata>(), nullptr,
+                             arena, call_arena_allocator_, nullptr);
+    Poll<ServerMetadataHandle> trailing_md;
+    call.initiator.SpawnInfallible(
+        "run_call", [destination, &call, &trailing_md]() mutable {
+          gpr_log(GPR_INFO, "👊 start call");
+          destination->StartCall(std::move(call.handler));
+          return Map(call.initiator.PullServerTrailingMetadata(),
+                     [&trailing_md](ServerMetadataHandle md) {
+                       trailing_md = std::move(md);
+                       return Empty{};
+                     });
+        });
+    EXPECT_THAT(trailing_md, IsReady());
+    return FinishedCall{std::move(call.initiator), destination_->TakeMetadata(),
+                        std::move(trailing_md.value())};
+  }
+
+ private:
+  class Destination final : public UnstartedCallDestination {
+   public:
+    void StartCall(UnstartedCallHandler unstarted_call_handler) override {
+      gpr_log(GPR_INFO, "👊 started call: metadata=%s",
+              unstarted_call_handler.UnprocessedClientInitialMetadata()
+                  .DebugString()
+                  .c_str());
+      EXPECT_EQ(metadata_.get(), nullptr);
+      metadata_ = Arena::MakePooled<ClientMetadata>();
+      *metadata_ =
+          unstarted_call_handler.UnprocessedClientInitialMetadata().Copy();
+      unstarted_call_handler.PushServerTrailingMetadata(
+          ServerMetadataFromStatus(absl::InternalError("👊 cancelled")));
+    }
+
+    void Orphaned() override {}
+
+    ClientMetadataHandle TakeMetadata() { return std::move(metadata_); }
+
+   private:
+    ClientMetadataHandle metadata_;
+  };
+  RefCountedPtr<Destination> destination_ = MakeRefCounted<Destination>();
+  RefCountedPtr<CallArenaAllocator> call_arena_allocator_ =
+      MakeRefCounted<CallArenaAllocator>(
+          ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator(
+              "test"),
+          1024);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Tests begin
+
+TEST_F(InterceptionChainTest, Empty) {
+  auto r = InterceptionChainBuilder(ChannelArgs()).Build(destination());
+  ASSERT_TRUE(r.ok()) << r.status();
+  auto finished_call = RunCall(r.value().get());
+  EXPECT_EQ(finished_call.server_metadata->get(GrpcStatusMetadata()),
+            GRPC_STATUS_INTERNAL);
+  EXPECT_EQ(finished_call.server_metadata->get_pointer(GrpcMessageMetadata())
+                ->as_string_view(),
+            "👊 cancelled");
+  EXPECT_NE(finished_call.client_metadata, nullptr);
+}
+
+TEST_F(InterceptionChainTest, Consumed) {
+  auto r = InterceptionChainBuilder(ChannelArgs())
+               .Add<TestConsumingInterceptor<1>>()
+               .Build(destination());
+  ASSERT_TRUE(r.ok()) << r.status();
+  auto finished_call = RunCall(r.value().get());
+  EXPECT_EQ(finished_call.server_metadata->get(GrpcStatusMetadata()),
+            GRPC_STATUS_INTERNAL);
+  EXPECT_EQ(finished_call.server_metadata->get_pointer(GrpcMessageMetadata())
+                ->as_string_view(),
+            "👊 consumed");
+  EXPECT_EQ(finished_call.client_metadata, nullptr);
+}
+
+TEST_F(InterceptionChainTest, Hijacked) {
+  auto r = InterceptionChainBuilder(ChannelArgs())
+               .Add<TestHijackingInterceptor<1>>()
+               .Build(destination());
+  ASSERT_TRUE(r.ok()) << r.status();
+  auto finished_call = RunCall(r.value().get());
+  EXPECT_EQ(finished_call.server_metadata->get(GrpcStatusMetadata()),
+            GRPC_STATUS_INTERNAL);
+  EXPECT_EQ(finished_call.server_metadata->get_pointer(GrpcMessageMetadata())
+                ->as_string_view(),
+            "👊 cancelled");
+  EXPECT_NE(finished_call.client_metadata, nullptr);
+}
+
+TEST_F(InterceptionChainTest, FiltersThenHijacked) {
+  auto r = InterceptionChainBuilder(ChannelArgs())
+               .Add<TestFilter<1>>()
+               .Add<TestHijackingInterceptor<2>>()
+               .Build(destination());
+  ASSERT_TRUE(r.ok()) << r.status();
+  auto finished_call = RunCall(r.value().get());
+  EXPECT_EQ(finished_call.server_metadata->get(GrpcStatusMetadata()),
+            GRPC_STATUS_INTERNAL);
+  EXPECT_EQ(finished_call.server_metadata->get_pointer(GrpcMessageMetadata())
+                ->as_string_view(),
+            "👊 cancelled");
+  EXPECT_NE(finished_call.client_metadata, nullptr);
+  std::string backing;
+  EXPECT_EQ(finished_call.client_metadata->GetStringValue("passed-through-1",
+                                                          &backing),
+            "true");
+}
+
+TEST_F(InterceptionChainTest, FailsToInstantiateInterceptor) {
+  auto r = InterceptionChainBuilder(ChannelArgs())
+               .Add<TestFailingInterceptor<1>>()
+               .Build(destination());
+  EXPECT_FALSE(r.ok());
+  EXPECT_EQ(r.status().code(), absl::StatusCode::kInternal);
+  EXPECT_EQ(r.status().message(), "👊 failed to instantiate 1");
+}
+
+TEST_F(InterceptionChainTest, FailsToInstantiateInterceptor2) {
+  auto r = InterceptionChainBuilder(ChannelArgs())
+               .Add<TestFilter<1>>()
+               .Add<TestFailingInterceptor<2>>()
+               .Build(destination());
+  EXPECT_FALSE(r.ok());
+  EXPECT_EQ(r.status().code(), absl::StatusCode::kInternal);
+  EXPECT_EQ(r.status().message(), "👊 failed to instantiate 2");
+}
+
+TEST_F(InterceptionChainTest, FailsToInstantiateFilter) {
+  auto r = InterceptionChainBuilder(ChannelArgs())
+               .Add<FailsToInstantiateFilter<1>>()
+               .Build(destination());
+  EXPECT_FALSE(r.ok());
+  EXPECT_EQ(r.status().code(), absl::StatusCode::kInternal);
+  EXPECT_EQ(r.status().message(), "👊 failed to instantiate 1");
+}
+
+TEST_F(InterceptionChainTest, FailsToInstantiateFilter2) {
+  auto r = InterceptionChainBuilder(ChannelArgs())
+               .Add<TestFilter<1>>()
+               .Add<FailsToInstantiateFilter<2>>()
+               .Build(destination());
+  EXPECT_FALSE(r.ok());
+  EXPECT_EQ(r.status().code(), absl::StatusCode::kInternal);
+  EXPECT_EQ(r.status().message(), "👊 failed to instantiate 2");
+}
+
+TEST_F(InterceptionChainTest, CreationOrderCorrect) {
+  CreationLog log;
+  auto r = InterceptionChainBuilder(ChannelArgs().SetObject(&log))
+               .Add<TestFilter<1>>()
+               .Add<TestFilter<2>>()
+               .Add<TestFilter<3>>()
+               .Add<TestConsumingInterceptor<4>>()
+               .Add<TestFilter<1>>()
+               .Add<TestFilter<2>>()
+               .Add<TestFilter<3>>()
+               .Add<TestConsumingInterceptor<4>>()
+               .Add<TestFilter<1>>()
+               .Build(destination());
+  EXPECT_THAT(log.entries, ::testing::ElementsAre(
+                               CreationLogEntry{0, 1}, CreationLogEntry{0, 2},
+                               CreationLogEntry{0, 3}, CreationLogEntry{0, 4},
+                               CreationLogEntry{1, 1}, CreationLogEntry{1, 2},
+                               CreationLogEntry{1, 3}, CreationLogEntry{1, 4},
+                               CreationLogEntry{2, 1}));
+}
+
+}  // namespace
+}  // namespace grpc_core
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  grpc_tracer_init();
+  gpr_log_verbosity_init();
+  return RUN_ALL_TESTS();
+}
diff --git a/test/core/transport/test_suite/test.cc b/test/core/transport/test_suite/test.cc
index 7dc767810d7..e170c9acda6 100644
--- a/test/core/transport/test_suite/test.cc
+++ b/test/core/transport/test_suite/test.cc
@@ -58,8 +58,7 @@ void TransportTest::SetServerAcceptor() {
 
 CallInitiator TransportTest::CreateCall(
     ClientMetadataHandle client_initial_metadata) {
-  auto call = MakeCall(std::move(client_initial_metadata), event_engine_.get(),
-                       Arena::Create(1024, &allocator_), true);
+  auto call = MakeCall(std::move(client_initial_metadata));
   call.handler.SpawnInfallible(
       "start-call", [this, handler = call.handler]() mutable {
         transport_pair_.client->client_transport()->StartCall(
@@ -231,13 +230,14 @@ std::string TransportTest::RandomMessage() {
 // TransportTest::Acceptor
 
 Arena* TransportTest::Acceptor::CreateArena() {
-  return Arena::Create(1024, allocator_);
+  return test_->call_arena_allocator_->MakeArena();
 }
 
 absl::StatusOr<CallInitiator> TransportTest::Acceptor::CreateCall(
     ClientMetadataHandle client_initial_metadata, Arena* arena) {
-  auto call =
-      MakeCall(std::move(client_initial_metadata), event_engine_, arena, true);
+  auto call = MakeCallPair(std::move(client_initial_metadata),
+                           test_->event_engine_.get(), arena,
+                           test_->call_arena_allocator_, nullptr);
   handlers_.push(call.handler.V2HackToStartCallWithoutACallFilterStack());
   return std::move(call.initiator);
 }
diff --git a/test/core/transport/test_suite/test.h b/test/core/transport/test_suite/test.h
index 5b0862a2744..1add21cdd29 100644
--- a/test/core/transport/test_suite/test.h
+++ b/test/core/transport/test_suite/test.h
@@ -86,10 +86,11 @@ class ActionState {
   explicit ActionState(NameAndLocation name_and_location);
 
   State Get() const { return state_; }
-  void Set(State state) {
+  void Set(State state, SourceLocation whence = {}) {
     gpr_log(GPR_INFO, "%s",
             absl::StrCat(StateString(state), " ", name(), " [", step(), "] ",
-                         file(), ":", line())
+                         file(), ":", line(), " @ ", whence.file(), ":",
+                         whence.line())
                 .c_str());
     state_ = state;
   }
@@ -237,6 +238,12 @@ class TransportTest : public ::testing::Test {
   CallHandler TickUntilServerCall();
   void WaitForAllPendingWork();
 
+  auto MakeCall(ClientMetadataHandle client_initial_metadata) {
+    auto* arena = call_arena_allocator_->MakeArena();
+    return MakeCallPair(std::move(client_initial_metadata), event_engine_.get(),
+                        arena, call_arena_allocator_, nullptr);
+  }
+
   // Alternative for Seq for test driver code.
   // Registers each step so that WaitForAllPendingWork() can report progress,
   // and wait for completion... AND generate good failure messages when a
@@ -265,9 +272,7 @@ class TransportTest : public ::testing::Test {
 
   class Acceptor final : public ServerTransport::Acceptor {
    public:
-    Acceptor(grpc_event_engine::experimental::EventEngine* event_engine,
-             MemoryAllocator* allocator)
-        : event_engine_(event_engine), allocator_(allocator) {}
+    explicit Acceptor(TransportTest* test) : test_(test) {}
 
     Arena* CreateArena() override;
     absl::StatusOr<CallInitiator> CreateCall(
@@ -276,8 +281,7 @@ class TransportTest : public ::testing::Test {
 
    private:
     std::queue<CallHandler> handlers_;
-    grpc_event_engine::experimental::EventEngine* const event_engine_;
-    MemoryAllocator* const allocator_;
+    TransportTest* const test_;
   };
 
   class WatchDog {
@@ -303,10 +307,13 @@ class TransportTest : public ::testing::Test {
               }(),
               fuzzing_event_engine::Actions())};
   std::unique_ptr<TransportFixture> fixture_;
-  MemoryAllocator allocator_ = MakeResourceQuota("test-quota")
-                                   ->memory_quota()
-                                   ->CreateMemoryAllocator("test-allocator");
-  Acceptor acceptor_{event_engine_.get(), &allocator_};
+  RefCountedPtr<CallArenaAllocator> call_arena_allocator_{
+      MakeRefCounted<CallArenaAllocator>(
+          MakeResourceQuota("test-quota")
+              ->memory_quota()
+              ->CreateMemoryAllocator("test-allocator"),
+          1024)};
+  Acceptor acceptor_{this};
   TransportFixture::ClientAndServerTransportPair transport_pair_ =
       fixture_->CreateTransportPair(event_engine_);
   std::queue<std::shared_ptr<transport_test_detail::ActionState>>
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 58ff43e6228..3cc34f6b422 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -2804,12 +2804,12 @@ src/core/lib/transport/batch_builder.cc \
 src/core/lib/transport/batch_builder.h \
 src/core/lib/transport/bdp_estimator.cc \
 src/core/lib/transport/bdp_estimator.h \
+src/core/lib/transport/call_arena_allocator.cc \
+src/core/lib/transport/call_arena_allocator.h \
 src/core/lib/transport/call_filters.cc \
 src/core/lib/transport/call_filters.h \
 src/core/lib/transport/call_final_info.cc \
 src/core/lib/transport/call_final_info.h \
-src/core/lib/transport/call_size_estimator.cc \
-src/core/lib/transport/call_size_estimator.h \
 src/core/lib/transport/call_spine.cc \
 src/core/lib/transport/call_spine.h \
 src/core/lib/transport/connectivity_state.cc \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index d17727a5592..ba38607ea8d 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -2581,12 +2581,12 @@ src/core/lib/transport/batch_builder.cc \
 src/core/lib/transport/batch_builder.h \
 src/core/lib/transport/bdp_estimator.cc \
 src/core/lib/transport/bdp_estimator.h \
+src/core/lib/transport/call_arena_allocator.cc \
+src/core/lib/transport/call_arena_allocator.h \
 src/core/lib/transport/call_filters.cc \
 src/core/lib/transport/call_filters.h \
 src/core/lib/transport/call_final_info.cc \
 src/core/lib/transport/call_final_info.h \
-src/core/lib/transport/call_size_estimator.cc \
-src/core/lib/transport/call_size_estimator.h \
 src/core/lib/transport/call_spine.cc \
 src/core/lib/transport/call_spine.h \
 src/core/lib/transport/connectivity_state.cc \
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 1503f00d037..61b98ca9bd1 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -5103,6 +5103,30 @@
     ],
     "uses_polling": false
   },
+  {
+    "args": [],
+    "benchmark": false,
+    "ci_platforms": [
+      "linux",
+      "mac",
+      "posix",
+      "windows"
+    ],
+    "cpu_cost": 1.0,
+    "exclude_configs": [],
+    "exclude_iomgrs": [],
+    "flaky": false,
+    "gtest": true,
+    "language": "c++",
+    "name": "interception_chain_test",
+    "platforms": [
+      "linux",
+      "mac",
+      "posix",
+      "windows"
+    ],
+    "uses_polling": false
+  },
   {
     "args": [],
     "benchmark": false,

From 4da74a52a0b57dda61b07923ec3a6160b78ed872 Mon Sep 17 00:00:00 2001
From: AJ Heller <hork@google.com>
Date: Wed, 24 Apr 2024 12:07:36 -0700
Subject: [PATCH 3/5] [build] Restrict visibility of grpc_public_hdrs and
 grpc++_public_hdrs (#36289)

These likely should have been internal targets, but they have been public for some time. External targets should depend on `//:grpc` or `//:grpc++` instead.

Closes #36289

COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/36289 from drfloob:restrict-grpc_public_hdrs 16f6c72ab6c047799596dca06b117f8711e50038
PiperOrigin-RevId: 627808418
---
 BUILD                       | 4 +++-
 bazel/grpc_build_system.bzl | 3 +++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/BUILD b/BUILD
index 406e42294d8..9872dc58e5e 100644
--- a/BUILD
+++ b/BUILD
@@ -823,6 +823,7 @@ grpc_cc_library(
         "avoid_dep",
         "nofixdeps",
     ],
+    visibility = ["@grpc:gpr_public_hdrs"],
 )
 
 grpc_cc_library(
@@ -885,6 +886,7 @@ grpc_cc_library(
         "avoid_dep",
         "nofixdeps",
     ],
+    visibility = ["@grpc:grpc_public_hdrs"],
     deps = [
         "channel_arg_names",
         "gpr_public_hdrs",
@@ -904,7 +906,7 @@ grpc_cc_library(
         "avoid_dep",
         "nofixdeps",
     ],
-    visibility = ["@grpc:public"],
+    visibility = ["@grpc:grpc++_public_hdrs"],
     deps = [
         "grpc_public_hdrs",
         "//src/core:gpr_atm",
diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl
index 54bb074ab2e..b839af3e7d8 100644
--- a/bazel/grpc_build_system.bzl
+++ b/bazel/grpc_build_system.bzl
@@ -106,11 +106,14 @@ def _update_visibility(visibility):
         "debug_location": PRIVATE,
         "endpoint_tests": PRIVATE,
         "exec_ctx": PRIVATE,
+        "gpr_public_hdrs": PRIVATE,
         "grpclb": PRIVATE,
         "grpc_experiments": PRIVATE,
         "grpc_opencensus_plugin": PUBLIC,
+        "grpc_public_hdrs": PRIVATE,
         "grpcpp_gcp_observability": PUBLIC,
         "grpc_resolver_fake": PRIVATE,
+        "grpc++_public_hdrs": PUBLIC,
         "grpc++_test": PRIVATE,
         "http": PRIVATE,
         "httpcli": PRIVATE,

From 4fdd2a8786e08977a606a128d96cf7f3821de66e Mon Sep 17 00:00:00 2001
From: Tanvi Jagtap <139093547+tanvi-jagtap@users.noreply.github.com>
Date: Wed, 24 Apr 2024 19:23:45 -0700
Subject: [PATCH 4/5] [grpc][Gpr_To_Absl_Logging] Migrating from gpr to absl
 logging GPR_ASSERT (#36436)

[grpc][Gpr_To_Absl_Logging] Migrating from gpr to absl logging GPR_ASSERT
Replacing GPR_ASSERT with absl CHECK

These changes have been made using string replacement and regex.

Will not be replacing all instances of CHECK with CHECK_EQ , CHECK_NE etc because there are too many callsites. Only ones which are doable using very simple regex with least chance of failure will be replaced.

Given that we have 5000+ instances of GPR_ASSERT to edit, Doing it manually is too much work for both the author and reviewer.

<!--

If you know who should review your pull request, please assign it to that
person, otherwise the pull request would get assigned randomly.

If your pull request is for a specific language, please add the appropriate
lang label.

-->

Closes #36436

COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/36436 from tanvi-jagtap:tjagtap_core_transport 8e25f5ae7bc12be334ada37e16c59e401b3c853a
PiperOrigin-RevId: 627925972
---
 CMakeLists.txt                                       |  1 +
 build_autogenerated.yaml                             |  1 +
 test/core/transport/BUILD                            |  1 +
 test/core/transport/binder/end2end/BUILD             |  2 +-
 test/core/transport/binder/end2end/fuzzers/BUILD     |  3 +++
 .../binder/end2end/fuzzers/client_fuzzer.cc          |  7 ++++---
 .../transport/binder/end2end/fuzzers/fuzzer_utils.cc |  4 +++-
 .../binder/end2end/fuzzers/server_fuzzer.cc          | 12 +++++++-----
 .../binder/end2end/testing_channel_create.cc         |  6 ++++--
 test/core/transport/chaotic_good/BUILD               |  3 +++
 .../chaotic_good/chaotic_good_server_test.cc         |  9 +++++----
 test/core/transport/chaotic_good/frame_fuzzer.cc     | 11 ++++++-----
 test/core/transport/chaotic_good/frame_test.cc       | 11 ++++++-----
 test/core/transport/chttp2/flow_control_fuzzer.cc    |  2 +-
 .../chttp2/remove_stream_from_stalled_lists_test.cc  |  2 +-
 ...ream_leak_with_queued_flow_control_update_test.cc |  4 ++--
 test/core/transport/chttp2/streams_not_seen_test.cc  |  2 +-
 test/core/transport/chttp2/too_many_pings_test.cc    |  6 +++---
 test/core/transport/parsed_metadata_test.cc          |  7 ++++---
 test/core/transport/test_suite/BUILD                 |  5 ++++-
 .../transport/test_suite/chaotic_good_fixture.cc     |  7 ++++---
 test/core/transport/test_suite/fuzzer_main.cc        |  8 +++++---
 .../transport/test_suite/grpc_transport_test.bzl     |  1 +
 23 files changed, 71 insertions(+), 44 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index f227cddcb6a..45e18642f2c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -21368,6 +21368,7 @@ target_include_directories(parsed_metadata_test
 target_link_libraries(parsed_metadata_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
+  absl::check
   grpc_test_util
 )
 
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index ca6c1d501a7..1366ec5ec02 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -14062,6 +14062,7 @@ targets:
   - test/core/transport/parsed_metadata_test.cc
   deps:
   - gtest
+  - absl/log:check
   - grpc_test_util
 - name: parser_test
   gtest: true
diff --git a/test/core/transport/BUILD b/test/core/transport/BUILD
index 519f3c3bc38..c52a096f429 100644
--- a/test/core/transport/BUILD
+++ b/test/core/transport/BUILD
@@ -116,6 +116,7 @@ grpc_cc_test(
     name = "parsed_metadata_test",
     srcs = ["parsed_metadata_test.cc"],
     external_deps = [
+        "absl/log:check",
         "gtest",
     ],
     language = "C++",
diff --git a/test/core/transport/binder/end2end/BUILD b/test/core/transport/binder/end2end/BUILD
index 30605e19fdf..cfc9a7f9614 100644
--- a/test/core/transport/binder/end2end/BUILD
+++ b/test/core/transport/binder/end2end/BUILD
@@ -63,7 +63,7 @@ grpc_cc_library(
     testonly = 1,
     srcs = ["testing_channel_create.cc"],
     hdrs = ["testing_channel_create.h"],
-    external_deps = [],
+    external_deps = ["absl/log:check"],
     deps = [
         ":fake_binder",
         "//:grpc++_base",
diff --git a/test/core/transport/binder/end2end/fuzzers/BUILD b/test/core/transport/binder/end2end/fuzzers/BUILD
index 85427723f08..bf8593e2cc7 100644
--- a/test/core/transport/binder/end2end/fuzzers/BUILD
+++ b/test/core/transport/binder/end2end/fuzzers/BUILD
@@ -35,6 +35,7 @@ grpc_proto_library(
 grpc_cc_library(
     name = "fuzzer_utils",
     srcs = ["fuzzer_utils.cc"],
+    external_deps = ["absl/log:check"],
     language = "c++",
     public_hdrs = ["fuzzer_utils.h"],
     deps = [
@@ -53,6 +54,7 @@ grpc_proto_fuzzer(
         "client_fuzzer.cc",
     ],
     corpus = "binder_transport_client_fuzzer_corpus",
+    external_deps = ["absl/log:check"],
     owner = "binder",
     proto = "client.proto",
     tags = [
@@ -76,6 +78,7 @@ grpc_proto_fuzzer(
         "server_fuzzer.cc",
     ],
     corpus = "binder_transport_server_fuzzer_corpus",
+    external_deps = ["absl/log:check"],
     owner = "binder",
     proto = "server.proto",
     tags = [
diff --git a/test/core/transport/binder/end2end/fuzzers/client_fuzzer.cc b/test/core/transport/binder/end2end/fuzzers/client_fuzzer.cc
index dc1f3887110..fb194663f58 100644
--- a/test/core/transport/binder/end2end/fuzzers/client_fuzzer.cc
+++ b/test/core/transport/binder/end2end/fuzzers/client_fuzzer.cc
@@ -15,6 +15,7 @@
 #include <thread>
 #include <utility>
 
+#include "absl/log/check.h"
 #include "absl/memory/memory.h"
 
 #include <grpc/grpc.h>
@@ -110,7 +111,7 @@ DEFINE_PROTO_FUZZER(const binder_transport_fuzzer::Input& input) {
     grpc_call_error error = grpc_call_start_batch(
         call, ops, static_cast<size_t>(op - ops), tag(1), nullptr);
     int requested_calls = 1;
-    GPR_ASSERT(GRPC_CALL_OK == error);
+    CHECK_EQ(error, GRPC_CALL_OK);
     grpc_event ev;
     while (true) {
       grpc_core::ExecCtx::Get()->Flush();
@@ -135,13 +136,13 @@ DEFINE_PROTO_FUZZER(const binder_transport_fuzzer::Input& input) {
     for (int i = 0; i < requested_calls; i++) {
       ev = grpc_completion_queue_next(cq, gpr_inf_past(GPR_CLOCK_REALTIME),
                                       nullptr);
-      GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
+      CHECK(ev.type == GRPC_OP_COMPLETE);
     }
     grpc_completion_queue_shutdown(cq);
     for (int i = 0; i < requested_calls; i++) {
       ev = grpc_completion_queue_next(cq, gpr_inf_past(GPR_CLOCK_REALTIME),
                                       nullptr);
-      GPR_ASSERT(ev.type == GRPC_QUEUE_SHUTDOWN);
+      CHECK(ev.type == GRPC_QUEUE_SHUTDOWN);
     }
     grpc_call_unref(call);
     grpc_completion_queue_destroy(cq);
diff --git a/test/core/transport/binder/end2end/fuzzers/fuzzer_utils.cc b/test/core/transport/binder/end2end/fuzzers/fuzzer_utils.cc
index 7575a0e56ba..74d9f65665e 100644
--- a/test/core/transport/binder/end2end/fuzzers/fuzzer_utils.cc
+++ b/test/core/transport/binder/end2end/fuzzers/fuzzer_utils.cc
@@ -14,6 +14,8 @@
 
 #include "test/core/transport/binder/end2end/fuzzers/fuzzer_utils.h"
 
+#include "absl/log/check.h"
+
 namespace grpc_binder {
 namespace fuzzing {
 
@@ -23,7 +25,7 @@ std::thread* g_fuzzing_thread = nullptr;
 
 template <typename... Args>
 void CreateFuzzingThread(Args&&... args) {
-  GPR_ASSERT(g_fuzzing_thread == nullptr);
+  CHECK_EQ(g_fuzzing_thread, nullptr);
   g_fuzzing_thread = new std::thread(std::forward<Args>(args)...);
 }
 
diff --git a/test/core/transport/binder/end2end/fuzzers/server_fuzzer.cc b/test/core/transport/binder/end2end/fuzzers/server_fuzzer.cc
index 4472291cb7b..48ce0e6fcea 100644
--- a/test/core/transport/binder/end2end/fuzzers/server_fuzzer.cc
+++ b/test/core/transport/binder/end2end/fuzzers/server_fuzzer.cc
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "absl/log/check.h"
+
 #include <grpc/grpc.h>
 
 #include "src/core/ext/transport/binder/transport/binder_transport.h"
@@ -62,9 +64,9 @@ DEFINE_PROTO_FUZZER(const binder_transport_fuzzer::Input& input) {
     grpc_metadata_array_init(&request_metadata1);
     int requested_calls = 0;
 
-    GPR_ASSERT(GRPC_CALL_OK ==
-               grpc_server_request_call(server, &call1, &call_details1,
-                                        &request_metadata1, cq, cq, tag(1)));
+    CHECK(GRPC_CALL_OK ==
+          grpc_server_request_call(server, &call1, &call_details1,
+                                   &request_metadata1, cq, cq, tag(1)));
     requested_calls++;
 
     grpc_event ev;
@@ -111,7 +113,7 @@ DEFINE_PROTO_FUZZER(const binder_transport_fuzzer::Input& input) {
         grpc_core::ExecCtx::Get()->InvalidateNow();
       } while (ev.type != GRPC_OP_COMPLETE &&
                grpc_core::Timestamp::Now() < deadline);
-      GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
+      CHECK(ev.type == GRPC_OP_COMPLETE);
     }
     grpc_completion_queue_shutdown(cq);
     for (int i = 0; i <= requested_calls; i++) {
@@ -121,7 +123,7 @@ DEFINE_PROTO_FUZZER(const binder_transport_fuzzer::Input& input) {
         grpc_core::ExecCtx::Get()->InvalidateNow();
       } while (ev.type != GRPC_QUEUE_SHUTDOWN &&
                grpc_core::Timestamp::Now() < deadline);
-      GPR_ASSERT(ev.type == GRPC_QUEUE_SHUTDOWN);
+      CHECK(ev.type == GRPC_QUEUE_SHUTDOWN);
     }
     grpc_server_destroy(server);
     grpc_completion_queue_destroy(cq);
diff --git a/test/core/transport/binder/end2end/testing_channel_create.cc b/test/core/transport/binder/end2end/testing_channel_create.cc
index 1823498bf26..50d9470960e 100644
--- a/test/core/transport/binder/end2end/testing_channel_create.cc
+++ b/test/core/transport/binder/end2end/testing_channel_create.cc
@@ -16,6 +16,8 @@
 
 #include <utility>
 
+#include "absl/log/check.h"
+
 #include <grpcpp/security/binder_security_policy.h>
 
 #include "src/core/ext/transport/binder/transport/binder_transport.h"
@@ -124,9 +126,9 @@ grpc_channel* grpc_binder_channel_create_for_testing(
       grpc_binder::end2end_testing::CreateClientServerBindersPairForTesting();
   grpc_error_handle error = grpc_core::Server::FromC(server)->SetupTransport(
       server_transport, nullptr, server_args, nullptr);
-  GPR_ASSERT(error.ok());
+  CHECK_OK(error);
   auto channel = grpc_core::ChannelCreate(
       "binder", client_args, GRPC_CLIENT_DIRECT_CHANNEL, client_transport);
-  GPR_ASSERT(channel.ok());
+  CHECK_OK(channel);
   return channel->release()->c_ptr();
 }
diff --git a/test/core/transport/chaotic_good/BUILD b/test/core/transport/chaotic_good/BUILD
index c288be7ade5..0a61bcfb488 100644
--- a/test/core/transport/chaotic_good/BUILD
+++ b/test/core/transport/chaotic_good/BUILD
@@ -77,6 +77,7 @@ grpc_cc_test(
     name = "frame_test",
     srcs = ["frame_test.cc"],
     external_deps = [
+        "absl/log:check",
         "absl/random",
         "absl/status",
         "absl/status:statusor",
@@ -93,6 +94,7 @@ grpc_proto_fuzzer(
     srcs = ["frame_fuzzer.cc"],
     corpus = "frame_fuzzer_corpus",
     external_deps = [
+        "absl/log:check",
         "absl/random:bit_gen_ref",
         "absl/status:statusor",
     ],
@@ -221,6 +223,7 @@ grpc_cc_test(
     name = "chaotic_good_server_test",
     srcs = ["chaotic_good_server_test.cc"],
     external_deps = [
+        "absl/log:check",
         "absl/strings",
         "absl/time",
         "gtest",
diff --git a/test/core/transport/chaotic_good/chaotic_good_server_test.cc b/test/core/transport/chaotic_good/chaotic_good_server_test.cc
index 674e2639bb3..db17dfa2b56 100644
--- a/test/core/transport/chaotic_good/chaotic_good_server_test.cc
+++ b/test/core/transport/chaotic_good/chaotic_good_server_test.cc
@@ -18,6 +18,7 @@
 #include <string>
 #include <utility>
 
+#include "absl/log/check.h"
 #include "absl/strings/str_cat.h"
 #include "absl/time/time.h"
 #include "gmock/gmock.h"
@@ -66,8 +67,8 @@ class ChaoticGoodServerTest : public ::testing::Test {
     auto ev = grpc_completion_queue_pluck(
         shutdown_cq, nullptr, grpc_timeout_milliseconds_to_deadline(15000),
         nullptr);
-    GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
-    GPR_ASSERT(ev.tag == nullptr);
+    CHECK(ev.type == GRPC_OP_COMPLETE);
+    CHECK_EQ(ev.tag, nullptr);
     grpc_completion_queue_destroy(shutdown_cq);
     grpc_server_destroy(server_);
   }
@@ -82,8 +83,8 @@ class ChaoticGoodServerTest : public ::testing::Test {
 
   void ConstructConnector() {
     auto uri = URI::Parse("ipv6:" + addr_);
-    GPR_ASSERT(uri.ok());
-    GPR_ASSERT(grpc_parse_uri(*uri, &resolved_addr_));
+    CHECK_OK(uri);
+    CHECK(grpc_parse_uri(*uri, &resolved_addr_));
     args_.address = &resolved_addr_;
     args_.deadline = Timestamp::Now() + Duration::Seconds(5);
     args_.channel_args = channel_args();
diff --git a/test/core/transport/chaotic_good/frame_fuzzer.cc b/test/core/transport/chaotic_good/frame_fuzzer.cc
index b5a09ab1d80..ff2a7619922 100644
--- a/test/core/transport/chaotic_good/frame_fuzzer.cc
+++ b/test/core/transport/chaotic_good/frame_fuzzer.cc
@@ -18,6 +18,7 @@
 #include <limits>
 #include <memory>
 
+#include "absl/log/check.h"
 #include "absl/random/bit_gen_ref.h"
 #include "absl/status/statusor.h"
 
@@ -55,8 +56,8 @@ template <typename T>
 void AssertRoundTrips(const T& input, FrameType expected_frame_type) {
   HPackCompressor hpack_compressor;
   auto serialized = input.Serialize(&hpack_compressor);
-  GPR_ASSERT(serialized.control.Length() >=
-             24);  // Initial output buffer size is 64 byte.
+  CHECK(serialized.control.Length() >=
+        24);  // Initial output buffer size is 64 byte.
   uint8_t header_bytes[24];
   serialized.control.MoveFirstNBytesIntoBuffer(24, header_bytes);
   auto header = FrameHeader::Parse(header_bytes);
@@ -67,15 +68,15 @@ void AssertRoundTrips(const T& input, FrameType expected_frame_type) {
     }
     Crash("Failed to parse header");
   }
-  GPR_ASSERT(header->type == expected_frame_type);
+  CHECK(header->type == expected_frame_type);
   T output;
   HPackParser hpack_parser;
   DeterministicBitGen bitgen;
   auto deser = output.Deserialize(&hpack_parser, header.value(),
                                   absl::BitGenRef(bitgen), GetContext<Arena>(),
                                   std::move(serialized), FuzzerFrameLimits());
-  GPR_ASSERT(deser.ok());
-  GPR_ASSERT(output == input);
+  CHECK_OK(deser);
+  CHECK(output == input);
 }
 
 template <typename T>
diff --git a/test/core/transport/chaotic_good/frame_test.cc b/test/core/transport/chaotic_good/frame_test.cc
index e29df6536cd..15389751a76 100644
--- a/test/core/transport/chaotic_good/frame_test.cc
+++ b/test/core/transport/chaotic_good/frame_test.cc
@@ -16,6 +16,7 @@
 
 #include <cstdint>
 
+#include "absl/log/check.h"
 #include "absl/random/random.h"
 #include "absl/status/status.h"
 #include "absl/status/statusor.h"
@@ -34,15 +35,15 @@ template <typename T>
 void AssertRoundTrips(const T& input, FrameType expected_frame_type) {
   HPackCompressor hpack_compressor;
   auto serialized = input.Serialize(&hpack_compressor);
-  GPR_ASSERT(serialized.control.Length() >=
-             24);  // Initial output buffer size is 64 byte.
+  CHECK_GE(serialized.control.Length(),
+           24);  // Initial output buffer size is 64 byte.
   uint8_t header_bytes[24];
   serialized.control.MoveFirstNBytesIntoBuffer(24, header_bytes);
   auto header = FrameHeader::Parse(header_bytes);
   if (!header.ok()) {
     Crash("Failed to parse header");
   }
-  GPR_ASSERT(header->type == expected_frame_type);
+  CHECK(header->type == expected_frame_type);
   T output;
   HPackParser hpack_parser;
   absl::BitGen bitgen;
@@ -53,8 +54,8 @@ void AssertRoundTrips(const T& input, FrameType expected_frame_type) {
   auto deser =
       output.Deserialize(&hpack_parser, header.value(), absl::BitGenRef(bitgen),
                          arena.get(), std::move(serialized), TestFrameLimits());
-  GPR_ASSERT(deser.ok());
-  GPR_ASSERT(output == input);
+  CHECK_OK(deser);
+  CHECK(output == input);
 }
 
 TEST(FrameTest, SettingsFrameRoundTrips) {
diff --git a/test/core/transport/chttp2/flow_control_fuzzer.cc b/test/core/transport/chttp2/flow_control_fuzzer.cc
index f599331d818..2b802704208 100644
--- a/test/core/transport/chttp2/flow_control_fuzzer.cc
+++ b/test/core/transport/chttp2/flow_control_fuzzer.cc
@@ -246,7 +246,7 @@ void FlowControlFuzzer::Perform(const flow_control_fuzzer::Action& action) {
           bdp->AddIncomingBytes(stream_write.size);
         }
         StreamFlowControl::IncomingUpdateContext upd(&stream->fc);
-        CHECK(upd.RecvData(stream_write.size).ok());
+        CHECK_OK(upd.RecvData(stream_write.size));
         PerformAction(upd.MakeAction(), stream);
       }
       send_from_remote_.pop_front();
diff --git a/test/core/transport/chttp2/remove_stream_from_stalled_lists_test.cc b/test/core/transport/chttp2/remove_stream_from_stalled_lists_test.cc
index 3cdb2d9940f..7312bd27b78 100644
--- a/test/core/transport/chttp2/remove_stream_from_stalled_lists_test.cc
+++ b/test/core/transport/chttp2/remove_stream_from_stalled_lists_test.cc
@@ -200,7 +200,7 @@ class TestServer {
           grpc_call_error error = grpc_server_request_call(
               server_, &call, &call_details, &request_metadata_recv, call_cq,
               cq_, request_call_tag);
-          CHECK(error == GRPC_CALL_OK);
+          CHECK_EQ(error, GRPC_CALL_OK);
         }
       }
       grpc_event event = grpc_completion_queue_next(
diff --git a/test/core/transport/chttp2/stream_leak_with_queued_flow_control_update_test.cc b/test/core/transport/chttp2/stream_leak_with_queued_flow_control_update_test.cc
index 423ed40e584..c60ff6e240a 100644
--- a/test/core/transport/chttp2/stream_leak_with_queued_flow_control_update_test.cc
+++ b/test/core/transport/chttp2/stream_leak_with_queued_flow_control_update_test.cc
@@ -80,7 +80,7 @@ class TestServer {
     grpc_call* call;
     grpc_call_error error = grpc_server_request_call(
         server_, &call, &call_details, &request_metadata_recv, cq_, cq_, tag);
-    CHECK(error == GRPC_CALL_OK);
+    CHECK_EQ(error, GRPC_CALL_OK);
     grpc_event event = grpc_completion_queue_next(
         cq_, gpr_inf_future(GPR_CLOCK_REALTIME), nullptr);
     CHECK(event.type == GRPC_OP_COMPLETE);
@@ -112,7 +112,7 @@ class TestServer {
     op++;
     error = grpc_call_start_batch(call, ops, static_cast<size_t>(op - ops), tag,
                                   nullptr);
-    CHECK(error == GRPC_CALL_OK);
+    CHECK_EQ(error, GRPC_CALL_OK);
     event = grpc_completion_queue_next(cq_, gpr_inf_future(GPR_CLOCK_REALTIME),
                                        nullptr);
     CHECK(event.type == GRPC_OP_COMPLETE);
diff --git a/test/core/transport/chttp2/streams_not_seen_test.cc b/test/core/transport/chttp2/streams_not_seen_test.cc
index fe1626d48f4..55719646187 100644
--- a/test/core/transport/chttp2/streams_not_seen_test.cc
+++ b/test/core/transport/chttp2/streams_not_seen_test.cc
@@ -365,7 +365,7 @@ class StreamsNotSeenTest : public ::testing::Test {
   }
 
   static void OnWriteDone(void* arg, grpc_error_handle error) {
-    CHECK(error.ok());
+    CHECK_OK(error);
     Notification* on_write_done_notification_ = static_cast<Notification*>(arg);
     on_write_done_notification_->Notify();
   }
diff --git a/test/core/transport/chttp2/too_many_pings_test.cc b/test/core/transport/chttp2/too_many_pings_test.cc
index 474e2edb4b3..956cab7d394 100644
--- a/test/core/transport/chttp2/too_many_pings_test.cc
+++ b/test/core/transport/chttp2/too_many_pings_test.cc
@@ -442,7 +442,7 @@ grpc_core::Resolver::Result BuildResolverResult(
     if (!uri.ok()) {
       gpr_log(GPR_ERROR, "Failed to parse uri. Error: %s",
               uri.status().ToString().c_str());
-      CHECK(uri.ok());
+      CHECK_OK(uri);
     }
     grpc_resolved_address address;
     CHECK(grpc_parse_uri(*uri, &address));
@@ -702,8 +702,8 @@ void PerformCallWithResponsePayload(grpc_channel* channel, grpc_server* server,
   cqv.Verify();
 
   CHECK(status == GRPC_STATUS_OK);
-  CHECK(0 == grpc_slice_str_cmp(details, "xyz"));
-  CHECK(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
+  CHECK_EQ(grpc_slice_str_cmp(details, "xyz"), 0);
+  CHECK_EQ(grpc_slice_str_cmp(call_details.method, "/foo"), 0);
   CHECK_EQ(was_cancelled, 0);
   CHECK(byte_buffer_eq_slice(response_payload_recv, response_payload_slice));
 
diff --git a/test/core/transport/parsed_metadata_test.cc b/test/core/transport/parsed_metadata_test.cc
index 458df652bb4..3b54fe2b535 100644
--- a/test/core/transport/parsed_metadata_test.cc
+++ b/test/core/transport/parsed_metadata_test.cc
@@ -18,6 +18,7 @@
 
 #include <memory>
 
+#include "absl/log/check.h"
 #include "absl/strings/numbers.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
@@ -55,7 +56,7 @@ struct Int32Trait {
   static int32_t MementoToValue(int32_t memento) { return memento; }
   static int32_t ParseMemento(Slice slice, bool, MetadataParseErrorFn) {
     int32_t out;
-    GPR_ASSERT(absl::SimpleAtoi(slice.as_string_view(), &out));
+    CHECK(absl::SimpleAtoi(slice.as_string_view(), &out));
     return out;
   }
   static std::string DisplayValue(int32_t value) {
@@ -75,7 +76,7 @@ struct Int64Trait {
   static int64_t MementoToValue(int64_t memento) { return -memento; }
   static int64_t ParseMemento(Slice slice, bool, MetadataParseErrorFn) {
     int64_t out;
-    GPR_ASSERT(absl::SimpleAtoi(slice.as_string_view(), &out));
+    CHECK(absl::SimpleAtoi(slice.as_string_view(), &out));
     return out;
   }
   static std::string DisplayValue(int64_t value) {
@@ -95,7 +96,7 @@ struct IntptrTrait {
   static intptr_t MementoToValue(intptr_t memento) { return memento / 2; }
   static intptr_t ParseMemento(Slice slice, bool, MetadataParseErrorFn) {
     intptr_t out;
-    GPR_ASSERT(absl::SimpleAtoi(slice.as_string_view(), &out));
+    CHECK(absl::SimpleAtoi(slice.as_string_view(), &out));
     return out;
   }
   static std::string DisplayValue(intptr_t value) {
diff --git a/test/core/transport/test_suite/BUILD b/test/core/transport/test_suite/BUILD
index 4bc8d7fcaa2..c42b8c6ece4 100644
--- a/test/core/transport/test_suite/BUILD
+++ b/test/core/transport/test_suite/BUILD
@@ -48,7 +48,10 @@ grpc_cc_library(
     name = "chaotic_good_fixture",
     testonly = 1,
     srcs = ["chaotic_good_fixture.cc"],
-    external_deps = ["gtest"],
+    external_deps = [
+        "absl/log:check",
+        "gtest",
+    ],
     deps = [
         "fixture",
         "//src/core:chaotic_good_client_transport",
diff --git a/test/core/transport/test_suite/chaotic_good_fixture.cc b/test/core/transport/test_suite/chaotic_good_fixture.cc
index d13ac3964bb..e1e0baff5e9 100644
--- a/test/core/transport/test_suite/chaotic_good_fixture.cc
+++ b/test/core/transport/test_suite/chaotic_good_fixture.cc
@@ -14,6 +14,7 @@
 
 #include <memory>
 
+#include "absl/log/check.h"
 #include "gmock/gmock.h"
 
 #include "src/core/ext/transport/chaotic_good/client_transport.h"
@@ -67,13 +68,13 @@ EndpointPair CreateEndpointPair(
       [](absl::Status) {}, endpoint_config,
       std::make_unique<MemoryQuotaBasedMemoryAllocatorFactory>(
           resource_quota->memory_quota()));
-  GPR_ASSERT(listener->Bind(resolved_address).ok());
-  GPR_ASSERT(listener->Start().ok());
+  CHECK_OK(listener->Bind(resolved_address));
+  CHECK_OK(listener->Start());
 
   event_engine->Connect(
       [&client_endpoint](
           absl::StatusOr<std::unique_ptr<EventEngine::Endpoint>> endpoint) {
-        GPR_ASSERT(endpoint.ok());
+        CHECK_OK(endpoint);
         client_endpoint = std::move(endpoint).value();
       },
       resolved_address, endpoint_config,
diff --git a/test/core/transport/test_suite/fuzzer_main.cc b/test/core/transport/test_suite/fuzzer_main.cc
index 3ee0fc65297..45a73e97afc 100644
--- a/test/core/transport/test_suite/fuzzer_main.cc
+++ b/test/core/transport/test_suite/fuzzer_main.cc
@@ -16,6 +16,8 @@
 
 #include <gtest/gtest.h>
 
+#include "absl/log/check.h"
+
 #include <grpc/event_engine/event_engine.h>
 #include <grpc/support/log.h>
 
@@ -37,8 +39,8 @@ static void dont_log(gpr_log_func_args* /*args*/) {}
 DEFINE_PROTO_FUZZER(const transport_test_suite::Msg& msg) {
   const auto& tests = grpc_core::TransportTestRegistry::Get().tests();
   const auto& fixtures = grpc_core::TransportFixtureRegistry::Get().fixtures();
-  GPR_ASSERT(!tests.empty());
-  GPR_ASSERT(!fixtures.empty());
+  CHECK(!tests.empty());
+  CHECK(!fixtures.empty());
   const int test_id = msg.test_id() % tests.size();
   const int fixture_id = msg.fixture_id() % fixtures.size();
 
@@ -62,5 +64,5 @@ DEFINE_PROTO_FUZZER(const transport_test_suite::Msg& msg) {
                             msg.event_engine_actions(), bitgen);
   test->RunTest();
   delete test;
-  GPR_ASSERT(!::testing::Test::HasFailure());
+  CHECK(!::testing::Test::HasFailure());
 }
diff --git a/test/core/transport/test_suite/grpc_transport_test.bzl b/test/core/transport/test_suite/grpc_transport_test.bzl
index 071b02e48e3..9bd94d33e79 100644
--- a/test/core/transport/test_suite/grpc_transport_test.bzl
+++ b/test/core/transport/test_suite/grpc_transport_test.bzl
@@ -35,6 +35,7 @@ def grpc_transport_test(name, deps):
         srcs = ["fuzzer_main.cc"],
         tags = ["no_windows", "no_mac"],
         external_deps = [
+            "absl/log:check",
             "gtest",
         ],
         deps = [

From b0de95507c51b24279c267489891cdbcc250061c Mon Sep 17 00:00:00 2001
From: Tanvi Jagtap <139093547+tanvi-jagtap@users.noreply.github.com>
Date: Wed, 24 Apr 2024 22:43:54 -0700
Subject: [PATCH 5/5] [grpc][Gpr_To_Absl_Logging] Migrating from gpr to absl
 logging GPR_ASSERT (#36441)

[grpc][Gpr_To_Absl_Logging] Migrating from gpr to absl logging GPR_ASSERT
Replacing GPR_ASSERT with absl CHECK

These changes have been made using string replacement and regex.

Will not be replacing all instances of CHECK with CHECK_EQ , CHECK_NE etc because there are too many callsites. Only ones which are doable using very simple regex with least chance of failure will be replaced.

Given that we have 5000+ instances of GPR_ASSERT to edit, Doing it manually is too much work for both the author and reviewer.

<!--

If you know who should review your pull request, please assign it to that
person, otherwise the pull request would get assigned randomly.

If your pull request is for a specific language, please add the appropriate
lang label.

-->

Closes #36441

COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/36441 from tanvi-jagtap:tjagtap_util_01 ca1029292553077d25559938604e1e08fc4bbe2b
PiperOrigin-RevId: 627961969
---
 CMakeLists.txt                             | 64 +++-------------------
 build_autogenerated.yaml                   | 64 +++-------------------
 test/cpp/util/BUILD                        |  4 ++
 test/cpp/util/channelz_sampler.cc          | 13 +++--
 test/cpp/util/channelz_sampler_test.cc     |  9 +--
 test/cpp/util/cli_call.cc                  | 18 +++---
 test/cpp/util/create_test_channel.cc       |  9 +--
 test/cpp/util/test_credentials_provider.cc |  3 +-
 test/cpp/util/windows/BUILD                |  1 +
 test/cpp/util/windows/manifest_file.cc     |  3 +-
 10 files changed, 52 insertions(+), 136 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 45e18642f2c..98a626ebf8a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4793,6 +4793,7 @@ target_include_directories(grpc++_test_util
 )
 target_link_libraries(grpc++_test_util
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::check
   grpc++
   grpc_test_util
 )
@@ -7114,7 +7115,6 @@ target_include_directories(async_end2end_test
 target_link_libraries(async_end2end_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -8152,7 +8152,6 @@ target_include_directories(binder_server_test
 target_link_libraries(binder_server_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -9044,7 +9043,6 @@ target_include_directories(cancel_ares_query_test
 target_link_libraries(cancel_ares_query_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_config
   grpc++_test_util
 )
@@ -9659,7 +9657,6 @@ target_include_directories(cfstream_test
 target_link_libraries(cfstream_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -10077,7 +10074,6 @@ target_include_directories(channelz_service_test
 target_link_libraries(channelz_service_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpcpp_channelz
   grpc++_test_util
 )
@@ -10496,7 +10492,6 @@ target_include_directories(client_callback_end2end_test
 target_link_libraries(client_callback_end2end_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -10752,7 +10747,6 @@ target_include_directories(client_interceptors_end2end_test
 target_link_libraries(client_interceptors_end2end_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -10825,7 +10819,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(client_lb_end2end_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
@@ -11623,7 +11616,6 @@ target_include_directories(context_allocator_end2end_test
 target_link_libraries(context_allocator_end2end_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -11843,7 +11835,6 @@ target_include_directories(crl_provider_test
 target_link_libraries(crl_provider_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -12056,7 +12047,6 @@ target_include_directories(delegating_channel_test
 target_link_libraries(delegating_channel_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -12592,7 +12582,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(end2end_binder_transport_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
@@ -12658,7 +12647,6 @@ target_include_directories(end2end_test
 
 target_link_libraries(end2end_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  absl::check
   grpc++_test
   grpc++_test_util
 )
@@ -14216,7 +14204,6 @@ target_include_directories(flaky_network_test
 target_link_libraries(flaky_network_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -15250,7 +15237,6 @@ target_include_directories(grpc_authz_end2end_test
 target_link_libraries(grpc_authz_end2end_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc_authorization_provider
   grpc++_test_util
 )
@@ -15406,6 +15392,7 @@ target_include_directories(grpc_cli
 
 target_link_libraries(grpc_cli
   ${_gRPC_ALLTARGETS_LIBRARIES}
+  absl::check
   grpc++
   ${_gRPC_PROTOBUF_PROTOC_LIBRARIES}
   grpc++_test_config
@@ -16196,7 +16183,6 @@ target_include_directories(grpclb_api_test
 target_link_libraries(grpclb_api_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -16266,7 +16252,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(grpclb_end2end_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_config
     grpc++_test_util
   )
@@ -16654,7 +16639,6 @@ target_include_directories(health_service_end2end_test
 target_link_libraries(health_service_end2end_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -17079,7 +17063,6 @@ target_include_directories(http2_client
 
 target_link_libraries(http2_client
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  absl::check
   grpc++_test_config
   grpc++_test_util
 )
@@ -17387,7 +17370,6 @@ target_include_directories(hybrid_end2end_test
 target_link_libraries(hybrid_end2end_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -18221,7 +18203,6 @@ target_include_directories(interop_client
 
 target_link_libraries(interop_client
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  absl::check
   grpc++_test_config
   grpc++_test_util
 )
@@ -18276,7 +18257,6 @@ target_include_directories(interop_server
 
 target_link_libraries(interop_server
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  absl::check
   grpc++_test_config
   grpc++_test_util
 )
@@ -19895,7 +19875,6 @@ target_include_directories(message_allocator_end2end_test
 target_link_libraries(message_allocator_end2end_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -20696,7 +20675,6 @@ target_include_directories(nonblocking_test
 target_link_libraries(nonblocking_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -21068,7 +21046,6 @@ target_include_directories(otel_plugin_test
 target_link_libraries(otel_plugin_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   opentelemetry-cpp::api
   opentelemetry-cpp::metrics
   grpc++_test_util
@@ -22163,7 +22140,6 @@ target_include_directories(port_sharing_end2end_test
 target_link_libraries(port_sharing_end2end_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -22356,7 +22332,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(posix_event_engine_native_dns_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
@@ -22412,7 +22387,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(posix_event_engine_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
@@ -22911,7 +22885,6 @@ target_include_directories(proto_server_reflection_test
 target_link_libraries(proto_server_reflection_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_reflection
   grpc++_test_util
 )
@@ -23100,7 +23073,6 @@ target_include_directories(qps_json_driver
 
 target_link_libraries(qps_json_driver
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  absl::check
   grpc++_test_config
   grpc++_test_util
 )
@@ -23173,7 +23145,6 @@ target_include_directories(qps_worker
 
 target_link_libraries(qps_worker
   ${_gRPC_ALLTARGETS_LIBRARIES}
-  absl::check
   grpc++_test_config
   grpc++_test_util
 )
@@ -23358,7 +23329,6 @@ target_include_directories(raw_end2end_test
 target_link_libraries(raw_end2end_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -26532,7 +26502,6 @@ target_include_directories(rls_end2end_test
 target_link_libraries(rls_end2end_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_config
   grpc++_test_util
 )
@@ -26965,7 +26934,6 @@ target_include_directories(server_builder_plugin_test
 target_link_libraries(server_builder_plugin_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -27461,7 +27429,6 @@ target_include_directories(server_interceptors_end2end_test
 target_link_libraries(server_interceptors_end2end_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -27793,7 +27760,6 @@ target_include_directories(service_config_end2end_test
 target_link_libraries(service_config_end2end_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -28079,7 +28045,6 @@ target_include_directories(shutdown_test
 target_link_libraries(shutdown_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -30623,7 +30588,6 @@ target_include_directories(test_cpp_end2end_ssl_credentials_test
 target_link_libraries(test_cpp_end2end_ssl_credentials_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -31492,7 +31456,6 @@ target_include_directories(tls_credentials_test
 target_link_libraries(tls_credentials_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -31552,7 +31515,6 @@ target_include_directories(tls_key_export_test
 target_link_libraries(tls_key_export_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -31649,7 +31611,6 @@ target_include_directories(too_many_pings_test
 target_link_libraries(too_many_pings_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_config
   grpc++_test_util
 )
@@ -33303,6 +33264,7 @@ target_include_directories(xds_audit_logger_registry_test
 target_link_libraries(xds_audit_logger_registry_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
+  absl::check
   grpc++
   ${_gRPC_PROTOBUF_PROTOC_LIBRARIES}
   grpc_test_util
@@ -33621,7 +33583,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(xds_cluster_end2end_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
@@ -33917,7 +33878,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(xds_cluster_type_end2end_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
@@ -34003,6 +33963,7 @@ target_include_directories(xds_common_types_test
 target_link_libraries(xds_common_types_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
+  absl::check
   grpc++
   ${_gRPC_PROTOBUF_PROTOC_LIBRARIES}
   grpc_test_util
@@ -34179,7 +34140,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(xds_core_end2end_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
@@ -34241,7 +34201,6 @@ target_include_directories(xds_credentials_end2end_test
 target_link_libraries(xds_credentials_end2end_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
-  absl::check
   grpc++_test_util
 )
 
@@ -34475,7 +34434,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(xds_csds_end2end_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
@@ -34671,7 +34629,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(xds_end2end_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_config
     grpc++_test_util
   )
@@ -34911,7 +34868,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(xds_fallback_end2end_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
@@ -35094,7 +35050,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(xds_fault_injection_end2end_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
@@ -35228,6 +35183,7 @@ target_include_directories(xds_http_filters_test
 target_link_libraries(xds_http_filters_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
+  absl::check
   grpc++
   ${_gRPC_PROTOBUF_PROTOC_LIBRARIES}
   grpc_test_util
@@ -35346,6 +35302,7 @@ target_include_directories(xds_lb_policy_registry_test
 target_link_libraries(xds_lb_policy_registry_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
+  absl::check
   grpc++
   ${_gRPC_PROTOBUF_PROTOC_LIBRARIES}
   grpc_test_util
@@ -35488,6 +35445,7 @@ target_include_directories(xds_listener_resource_type_test
 target_link_libraries(xds_listener_resource_type_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
+  absl::check
   grpc++
   ${_gRPC_PROTOBUF_PROTOC_LIBRARIES}
   grpc_test_util
@@ -35671,7 +35629,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(xds_outlier_detection_end2end_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
@@ -35858,7 +35815,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(xds_override_host_end2end_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
@@ -36134,7 +36090,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(xds_pick_first_end2end_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
@@ -36314,7 +36269,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(xds_ring_hash_end2end_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
@@ -36498,7 +36452,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(xds_rls_end2end_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
@@ -36620,6 +36573,7 @@ target_include_directories(xds_route_config_resource_type_test
 target_link_libraries(xds_route_config_resource_type_test
   ${_gRPC_ALLTARGETS_LIBRARIES}
   gtest
+  absl::check
   grpc++
   ${_gRPC_PROTOBUF_PROTOC_LIBRARIES}
   grpc_test_util
@@ -36803,7 +36757,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(xds_routing_end2end_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
@@ -37066,7 +37019,6 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
   target_link_libraries(xds_wrr_end2end_test
     ${_gRPC_ALLTARGETS_LIBRARIES}
     gtest
-    absl::check
     grpc++_test_util
   )
 
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index 1366ec5ec02..4f0ba62388e 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -4052,6 +4052,7 @@ libs:
   - test/cpp/util/subprocess.cc
   - test/cpp/util/test_credentials_provider.cc
   deps:
+  - absl/log:check
   - grpc++
   - grpc_test_util
 - name: grpc++_unsecure
@@ -5643,7 +5644,6 @@ targets:
   - test/cpp/end2end/async_end2end_test.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: auth_context_test
   gtest: true
@@ -6134,7 +6134,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: binder_transport_test
   gtest: true
@@ -6899,7 +6898,6 @@ targets:
   - test/cpp/naming/cancel_ares_query_test.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_config
   - grpc++_test_util
 - name: cancel_before_invoke_test
@@ -7488,7 +7486,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: channel_args_test
   gtest: true
@@ -7618,7 +7615,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpcpp_channelz
   - grpc++_test_util
 - name: check_gcp_environment_linux_test
@@ -7888,7 +7884,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: client_channel_service_config_test
   gtest: true
@@ -7960,7 +7955,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: client_lb_end2end_test
   gtest: true
@@ -7985,7 +7979,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
@@ -8404,7 +8397,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: context_test
   gtest: true
@@ -8469,7 +8461,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: crl_ssl_transport_security_test
   gtest: true
@@ -8577,7 +8568,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: destroy_grpclb_channel_with_active_connect_stress_test
   gtest: true
@@ -8823,7 +8813,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
@@ -8846,7 +8835,6 @@ targets:
   - test/cpp/end2end/interceptors_util.cc
   - test/cpp/end2end/test_service_impl.cc
   deps:
-  - absl/log:check
   - grpc++_test
   - grpc++_test_util
 - name: endpoint_addresses_test
@@ -9822,7 +9810,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: flow_control_test
   gtest: true
@@ -10480,7 +10467,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc_authorization_provider
   - grpc++_test_util
 - name: grpc_authz_test
@@ -10580,6 +10566,7 @@ targets:
   - test/cpp/util/proto_reflection_descriptor_database.cc
   - test/cpp/util/service_describer.cc
   deps:
+  - absl/log:check
   - grpc++
   - protoc
   - grpc++_test_config
@@ -10894,7 +10881,6 @@ targets:
   - test/cpp/grpclb/grpclb_api_test.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: grpclb_end2end_test
   gtest: true
@@ -10915,7 +10901,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_config
   - grpc++_test_util
   platforms:
@@ -11056,7 +11041,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: high_initial_seqno_test
   gtest: true
@@ -11333,7 +11317,6 @@ targets:
   - src/proto/grpc/testing/test.proto
   - test/cpp/interop/http2_client.cc
   deps:
-  - absl/log:check
   - grpc++_test_config
   - grpc++_test_util
 - name: http2_settings_test
@@ -11474,7 +11457,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: idle_filter_state_test
   gtest: true
@@ -12389,7 +12371,6 @@ targets:
   - test/cpp/interop/client_helper.cc
   - test/cpp/interop/interop_client.cc
   deps:
-  - absl/log:check
   - grpc++_test_config
   - grpc++_test_util
 - name: interop_server
@@ -12407,7 +12388,6 @@ targets:
   - test/cpp/interop/interop_server_bootstrap.cc
   - test/cpp/interop/server_helper.cc
   deps:
-  - absl/log:check
   - grpc++_test_config
   - grpc++_test_util
 - name: invalid_call_argument_test
@@ -13412,7 +13392,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: message_compress_test
   gtest: true
@@ -13824,7 +13803,6 @@ targets:
   - test/cpp/end2end/nonblocking_test.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: notification_test
   gtest: true
@@ -13967,7 +13945,6 @@ targets:
   - test/cpp/ext/otel/otel_test_library.cc
   deps:
   - gtest
-  - absl/log:check
   - opentelemetry-cpp::api
   - opentelemetry-cpp::metrics
   - grpc++_test_util
@@ -14571,7 +14548,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: posix_endpoint_test
   gtest: true
@@ -14653,7 +14629,6 @@ targets:
   - test/cpp/util/windows/manifest_file.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
@@ -14687,7 +14662,6 @@ targets:
   - test/cpp/util/windows/manifest_file.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
@@ -14878,7 +14852,6 @@ targets:
   - test/cpp/util/proto_reflection_descriptor_database.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_reflection
   - grpc++_test_util
 - name: proto_utils_test
@@ -14997,7 +14970,6 @@ targets:
   - test/cpp/qps/server_sync.cc
   - test/cpp/qps/usage_timer.cc
   deps:
-  - absl/log:check
   - grpc++_test_config
   - grpc++_test_util
 - name: qps_worker
@@ -15031,7 +15003,6 @@ targets:
   - test/cpp/qps/usage_timer.cc
   - test/cpp/qps/worker.cc
   deps:
-  - absl/log:check
   - grpc++_test_config
   - grpc++_test_util
 - name: query_extensions_test
@@ -15091,7 +15062,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: rbac_service_config_parser_test
   gtest: true
@@ -17831,7 +17801,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_config
   - grpc++_test_util
 - name: rls_lb_config_parser_test
@@ -17996,7 +17965,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: server_builder_test
   gtest: true
@@ -18213,7 +18181,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: server_registered_method_bad_client_test
   gtest: true
@@ -18375,7 +18342,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: service_config_test
   gtest: true
@@ -18560,7 +18526,6 @@ targets:
   - test/cpp/end2end/shutdown_test.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: simple_delayed_request_test
   gtest: true
@@ -19781,7 +19746,6 @@ targets:
   - test/cpp/end2end/test_service_impl.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: test_cpp_ext_chaotic_good_test
   gtest: true
@@ -20127,7 +20091,6 @@ targets:
   - test/cpp/end2end/tls_credentials_test.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: tls_key_export_test
   gtest: true
@@ -20142,7 +20105,6 @@ targets:
   - test/cpp/end2end/tls_key_export_test.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: tls_security_connector_test
   gtest: true
@@ -20187,7 +20149,6 @@ targets:
   - test/core/transport/chttp2/too_many_pings_test.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_config
   - grpc++_test_util
 - name: traced_buffer_list_test
@@ -21131,6 +21092,7 @@ targets:
   - test/cpp/util/service_describer.cc
   deps:
   - gtest
+  - absl/log:check
   - grpc++
   - protoc
   - grpc_test_util
@@ -21235,7 +21197,6 @@ targets:
   - test/cpp/util/tls_test_utils.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
@@ -21328,7 +21289,6 @@ targets:
   - test/cpp/util/tls_test_utils.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
@@ -21363,6 +21323,7 @@ targets:
   - test/cpp/util/service_describer.cc
   deps:
   - gtest
+  - absl/log:check
   - grpc++
   - protoc
   - grpc_test_util
@@ -21422,7 +21383,6 @@ targets:
   - test/cpp/util/tls_test_utils.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
@@ -21443,7 +21403,6 @@ targets:
   - test/cpp/end2end/xds/xds_credentials_end2end_test.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
 - name: xds_credentials_test
   gtest: true
@@ -21530,7 +21489,6 @@ targets:
   - test/cpp/util/tls_test_utils.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
@@ -21596,7 +21554,6 @@ targets:
   - test/cpp/util/tls_test_utils.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_config
   - grpc++_test_util
   platforms:
@@ -21674,7 +21631,6 @@ targets:
   - test/cpp/util/tls_test_utils.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
@@ -21734,7 +21690,6 @@ targets:
   - test/cpp/util/tls_test_utils.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
@@ -21782,6 +21737,7 @@ targets:
   - test/cpp/util/service_describer.cc
   deps:
   - gtest
+  - absl/log:check
   - grpc++
   - protoc
   - grpc_test_util
@@ -21824,6 +21780,7 @@ targets:
   - test/cpp/util/service_describer.cc
   deps:
   - gtest
+  - absl/log:check
   - grpc++
   - protoc
   - grpc_test_util
@@ -21871,6 +21828,7 @@ targets:
   - test/cpp/util/service_describer.cc
   deps:
   - gtest
+  - absl/log:check
   - grpc++
   - protoc
   - grpc_test_util
@@ -21929,7 +21887,6 @@ targets:
   - test/cpp/util/tls_test_utils.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
@@ -21990,7 +21947,6 @@ targets:
   - test/cpp/util/tls_test_utils.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
@@ -22082,7 +22038,6 @@ targets:
   - test/cpp/util/tls_test_utils.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
@@ -22143,7 +22098,6 @@ targets:
   - test/cpp/util/tls_test_utils.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
@@ -22205,7 +22159,6 @@ targets:
   - test/cpp/util/tls_test_utils.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
@@ -22250,6 +22203,7 @@ targets:
   - test/cpp/util/service_describer.cc
   deps:
   - gtest
+  - absl/log:check
   - grpc++
   - protoc
   - grpc_test_util
@@ -22308,7 +22262,6 @@ targets:
   - test/cpp/util/tls_test_utils.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
@@ -22398,7 +22351,6 @@ targets:
   - test/cpp/util/tls_test_utils.cc
   deps:
   - gtest
-  - absl/log:check
   - grpc++_test_util
   platforms:
   - linux
diff --git a/test/cpp/util/BUILD b/test/cpp/util/BUILD
index fe324d5fa78..707c6db9524 100644
--- a/test/cpp/util/BUILD
+++ b/test/cpp/util/BUILD
@@ -77,6 +77,7 @@ grpc_cc_library(
     ],
     external_deps = [
         "absl/flags:flag",
+        "absl/log:check",
         "protobuf",
     ],
     deps = [
@@ -139,6 +140,7 @@ grpc_cc_library(
     ],
     external_deps = [
         "absl/flags:flag",
+        "absl/log:check",
         "protobuf",
         "protobuf_clib",
     ],
@@ -335,6 +337,7 @@ grpc_cc_binary(
     srcs = ["channelz_sampler.cc"],
     external_deps = [
         "absl/flags:flag",
+        "absl/log:check",
         "absl/strings",
     ],
     language = "c++",
@@ -360,6 +363,7 @@ grpc_cc_test(
         ":channelz_sampler",
     ],
     external_deps = [
+        "absl/log:check",
         "gtest",
     ],
     flaky = True,
diff --git a/test/cpp/util/channelz_sampler.cc b/test/cpp/util/channelz_sampler.cc
index 4515aa60e21..d5a79514595 100644
--- a/test/cpp/util/channelz_sampler.cc
+++ b/test/cpp/util/channelz_sampler.cc
@@ -27,6 +27,7 @@
 #include <string>
 
 #include "absl/flags/flag.h"
+#include "absl/log/check.h"
 #include "absl/strings/str_format.h"
 #include "absl/strings/str_join.h"
 #include "google/protobuf/text_format.h"
@@ -134,7 +135,7 @@ class ChannelzSampler final {
     if (!status.ok()) {
       gpr_log(GPR_ERROR, "GetChannelRPC failed: %s",
               get_channel_context.debug_error_string().c_str());
-      GPR_ASSERT(0);
+      CHECK(0);
     }
     return get_channel_response.channel();
   }
@@ -153,7 +154,7 @@ class ChannelzSampler final {
     if (!status.ok()) {
       gpr_log(GPR_ERROR, "GetSubchannelRPC failed: %s",
               get_subchannel_context.debug_error_string().c_str());
-      GPR_ASSERT(0);
+      CHECK(0);
     }
     return get_subchannel_response.subchannel();
   }
@@ -171,7 +172,7 @@ class ChannelzSampler final {
     if (!status.ok()) {
       gpr_log(GPR_ERROR, "GetSocketRPC failed: %s",
               get_socket_context.debug_error_string().c_str());
-      GPR_ASSERT(0);
+      CHECK(0);
     }
     return get_socket_response.socket();
   }
@@ -300,7 +301,7 @@ class ChannelzSampler final {
               "Wrong user credential type: %s. Allowed credential types: "
               "INSECURE_CREDENTIALS, ssl, alts, google_default_credentials.",
               custom_credentials_type.c_str());
-      GPR_ASSERT(0);
+      CHECK(0);
     }
     std::shared_ptr<grpc::Channel> channel =
         CreateChannel(server_address, channel_creds);
@@ -333,7 +334,7 @@ class ChannelzSampler final {
                   static_cast<int>(server_start_id),
                   get_servers_context.debug_error_string().c_str());
         }
-        GPR_ASSERT(0);
+        CHECK(0);
       }
       for (const auto& _server : get_servers_response.server()) {
         all_servers_.push_back(_server);
@@ -388,7 +389,7 @@ class ChannelzSampler final {
                 "GetTopChannelsRequest.channel_start_id=%d failed: %s",
                 static_cast<int>(channel_start_id),
                 get_top_channels_context.debug_error_string().c_str());
-        GPR_ASSERT(0);
+        CHECK(0);
       }
       for (const auto& _topchannel : get_top_channels_response.channel()) {
         top_channels_.push_back(_topchannel);
diff --git a/test/cpp/util/channelz_sampler_test.cc b/test/cpp/util/channelz_sampler_test.cc
index 3b5520a76e4..03ea7139a27 100644
--- a/test/cpp/util/channelz_sampler_test.cc
+++ b/test/cpp/util/channelz_sampler_test.cc
@@ -24,6 +24,7 @@
 #include <string>
 #include <thread>
 
+#include "absl/log/check.h"
 #include "absl/strings/str_cat.h"
 #include "gtest/gtest.h"
 
@@ -96,7 +97,7 @@ void RunClient(const std::string& client_id, gpr_event* done_ev) {
     Status status = stub->EmptyCall(&context, request, &response);
     if (!status.ok()) {
       gpr_log(GPR_ERROR, "Client echo failed.");
-      GPR_ASSERT(0);
+      CHECK(0);
     }
   }
 }
@@ -146,17 +147,17 @@ TEST(ChannelzSamplerTest, SimpleTest) {
       gpr_log(GPR_ERROR,
               "Channelz sampler test test-runner exited with code %d",
               WEXITSTATUS(status));
-      GPR_ASSERT(0);  // log the line number of the assertion failure
+      CHECK(0);  // log the line number of the assertion failure
     }
   } else if (WIFSIGNALED(status)) {
     gpr_log(GPR_ERROR, "Channelz sampler test test-runner ended from signal %d",
             WTERMSIG(status));
-    GPR_ASSERT(0);
+    CHECK(0);
   } else {
     gpr_log(GPR_ERROR,
             "Channelz sampler test test-runner ended with unknown status %d",
             status);
-    GPR_ASSERT(0);
+    CHECK(0);
   }
   delete test_driver;
   gpr_event_set(&done_ev1, reinterpret_cast<void*>(1));
diff --git a/test/cpp/util/cli_call.cc b/test/cpp/util/cli_call.cc
index 6e914e72820..df765c64a49 100644
--- a/test/cpp/util/cli_call.cc
+++ b/test/cpp/util/cli_call.cc
@@ -22,6 +22,8 @@
 #include <iostream>
 #include <utility>
 
+#include "absl/log/check.h"
+
 #include <grpc/grpc.h>
 #include <grpc/slice.h>
 #include <grpc/support/log.h>
@@ -81,7 +83,7 @@ CliCall::CliCall(const std::shared_ptr<grpc::Channel>& channel,
   void* got_tag;
   bool ok;
   cq_.Next(&got_tag, &ok);
-  GPR_ASSERT(ok);
+  CHECK(ok);
 }
 
 CliCall::~CliCall() {
@@ -98,7 +100,7 @@ void CliCall::Write(const std::string& request) {
   grpc::ByteBuffer send_buffer(&req_slice, 1);
   call_->Write(send_buffer, tag(2));
   cq_.Next(&got_tag, &ok);
-  GPR_ASSERT(ok);
+  CHECK(ok);
 }
 
 bool CliCall::Read(std::string* response,
@@ -113,7 +115,7 @@ bool CliCall::Read(std::string* response,
     return false;
   }
   std::vector<grpc::Slice> slices;
-  GPR_ASSERT(recv_buffer.Dump(&slices).ok());
+  CHECK(recv_buffer.Dump(&slices).ok());
 
   response->clear();
   for (size_t i = 0; i < slices.size(); i++) {
@@ -132,7 +134,7 @@ void CliCall::WritesDone() {
 
   call_->WritesDone(tag(4));
   cq_.Next(&got_tag, &ok);
-  GPR_ASSERT(ok);
+  CHECK(ok);
 }
 
 void CliCall::WriteAndWait(const std::string& request) {
@@ -175,7 +177,7 @@ bool CliCall::ReadAndMaybeNotifyWrite(
 
     cq_result = cq_.Next(&got_tag, &ok);
     if (got_tag == tag(2)) {
-      GPR_ASSERT(ok);
+      CHECK(ok);
     }
   }
 
@@ -186,7 +188,7 @@ bool CliCall::ReadAndMaybeNotifyWrite(
       gpr_mu_lock(&write_mu_);
       if (!write_done_) {
         cq_.Next(&got_tag, &ok);
-        GPR_ASSERT(got_tag != tag(2));
+        CHECK(got_tag != tag(2));
         write_done_ = true;
         gpr_cv_signal(&write_cv_);
       }
@@ -196,7 +198,7 @@ bool CliCall::ReadAndMaybeNotifyWrite(
   }
 
   std::vector<grpc::Slice> slices;
-  GPR_ASSERT(recv_buffer.Dump(&slices).ok());
+  CHECK(recv_buffer.Dump(&slices).ok());
   response->clear();
   for (size_t i = 0; i < slices.size(); i++) {
     response->append(reinterpret_cast<const char*>(slices[i].begin()),
@@ -215,7 +217,7 @@ Status CliCall::Finish(IncomingMetadataContainer* server_trailing_metadata) {
 
   call_->Finish(&status, tag(5));
   cq_.Next(&got_tag, &ok);
-  GPR_ASSERT(ok);
+  CHECK(ok);
   if (server_trailing_metadata) {
     *server_trailing_metadata = ctx_.GetServerTrailingMetadata();
   }
diff --git a/test/cpp/util/create_test_channel.cc b/test/cpp/util/create_test_channel.cc
index 6f5ad07ce7e..f5c3a9a037e 100644
--- a/test/cpp/util/create_test_channel.cc
+++ b/test/cpp/util/create_test_channel.cc
@@ -19,6 +19,7 @@
 #include "test/cpp/util/create_test_channel.h"
 
 #include "absl/flags/flag.h"
+#include "absl/log/check.h"
 
 #include <grpc/support/log.h>
 #include <grpcpp/create_channel.h>
@@ -135,7 +136,7 @@ std::shared_ptr<Channel> CreateTestChannel(
   std::shared_ptr<ChannelCredentials> channel_creds =
       testing::GetCredentialsProvider()->GetChannelCredentials(credential_type,
                                                                &channel_args);
-  GPR_ASSERT(channel_creds != nullptr);
+  CHECK_NE(channel_creds, nullptr);
   if (creds.get()) {
     channel_creds = grpc::CompositeChannelCredentials(channel_creds, creds);
   }
@@ -174,7 +175,7 @@ std::shared_ptr<Channel> CreateTestChannel(
       channel_creds = testing::GetCredentialsProvider()->GetChannelCredentials(
           testing::kTlsCredentialsType, &channel_args);
     }
-    GPR_ASSERT(channel_creds != nullptr);
+    CHECK_NE(channel_creds, nullptr);
 
     const std::string& connect_to = server.empty() ? override_hostname : server;
     if (creds.get()) {
@@ -190,7 +191,7 @@ std::shared_ptr<Channel> CreateTestChannel(
   } else {
     channel_creds = testing::GetCredentialsProvider()->GetChannelCredentials(
         cred_type, &channel_args);
-    GPR_ASSERT(channel_creds != nullptr);
+    CHECK_NE(channel_creds, nullptr);
 
     if (interceptor_creators.empty()) {
       return grpc::CreateCustomChannel(server, channel_creds, channel_args);
@@ -252,7 +253,7 @@ std::shared_ptr<Channel> CreateTestChannel(
   std::shared_ptr<ChannelCredentials> channel_creds =
       testing::GetCredentialsProvider()->GetChannelCredentials(credential_type,
                                                                &channel_args);
-  GPR_ASSERT(channel_creds != nullptr);
+  CHECK_NE(channel_creds, nullptr);
   if (creds.get()) {
     channel_creds = grpc::CompositeChannelCredentials(channel_creds, creds);
   }
diff --git a/test/cpp/util/test_credentials_provider.cc b/test/cpp/util/test_credentials_provider.cc
index 19504f5762c..c85de0a8b25 100644
--- a/test/cpp/util/test_credentials_provider.cc
+++ b/test/cpp/util/test_credentials_provider.cc
@@ -26,6 +26,7 @@
 #include <unordered_map>
 
 #include "absl/flags/flag.h"
+#include "absl/log/check.h"
 
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
@@ -176,7 +177,7 @@ CredentialsProvider* GetCredentialsProvider() {
 
 void SetCredentialsProvider(CredentialsProvider* provider) {
   // For now, forbids overriding provider.
-  GPR_ASSERT(g_provider == nullptr);
+  CHECK_EQ(g_provider, nullptr);
   g_provider = provider;
 }
 
diff --git a/test/cpp/util/windows/BUILD b/test/cpp/util/windows/BUILD
index ffd2352efd4..7bf6080b21b 100644
--- a/test/cpp/util/windows/BUILD
+++ b/test/cpp/util/windows/BUILD
@@ -31,6 +31,7 @@ grpc_cc_library(
         "manifest_file.h",
     ],
     external_deps = [
+        "absl/log:check",
         "absl/strings",
     ],
     deps = [
diff --git a/test/cpp/util/windows/manifest_file.cc b/test/cpp/util/windows/manifest_file.cc
index 455095dcc1e..0bf2c9d3f01 100644
--- a/test/cpp/util/windows/manifest_file.cc
+++ b/test/cpp/util/windows/manifest_file.cc
@@ -24,6 +24,7 @@
 #include <string>
 #include <vector>
 
+#include "absl/log/check.h"
 #include "absl/strings/str_format.h"
 #include "absl/strings/str_replace.h"
 #include "absl/strings/str_split.h"
@@ -57,7 +58,7 @@ std::string ManifestFile::Get(const std::string& key) {
     std::getline(filestream_, line);
     if (!line.empty()) {
       std::vector<std::string> kv = absl::StrSplit(line, " ");
-      GPR_ASSERT(kv.size() == 2);
+      CHECK_EQ(kv.size(), 2u);
       cache_.emplace(kv[0], kv[1]);
       if (kv[0] == key) {
         return kv[1];